/*
 * Form1.cs
 * Copyright (c) 2007-2009 kbinani
 *
 * This file is part of LipSync.
 *
 * LipSync is free software; you can redistribute it and/or
 * modify it under the terms of the BSD License.
 *
 * LipSync 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.
 */
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Windows.Forms;

using Boare.Lib.AppUtil;
using Boare.Lib.Media;
using Boare.Lib.Vsq;
using Plugin;
#if DEBUG
using Boare.Lib.Swf;
#endif

namespace LipSync {

    public partial class Form1 : Form, IMultiLanguageControl {
        #region Constants
        private const byte FILEFORMAT = 1;
        /// <summary>
        /// プレビューとタイムラインのシンクロを行うとき、次の画面へ移動する時の両側の重複部分の幅
        /// </summary>
        private const float SIDE_WIDTH = 0.15f;
        /// <summary>
        /// m_editHandleLeft, Rightの幅
        /// </summary>
        private const int HANDLE_WIDTH = 8;
        /// <summary>
        /// 自動スクロール適用直後、画面の中央が、現在の再生時刻位置まで滑らかに移動するブレンド時間
        /// </summary>
        private const float FIT_CENTER_BREND_TIME = 2f;
        const int BUF_LEN = 10;
        #endregion

        #region Static Readonly Field
        private static readonly AuthorListEntry[] m_credit = new AuthorListEntry[]{
            new AuthorListEntry( "is developped by:", FontStyle.Italic ),
            new AuthorListEntry( "kbinani" ),
            new AuthorListEntry( "and he thanks to:", FontStyle.Italic ),
            new AuthorListEntry(),
            new AuthorListEntry( "author of embedded character", FontStyle.Italic ),
            new AuthorListEntry( "さなり" ),
            new AuthorListEntry(),
            new AuthorListEntry( "contributors", FontStyle.Italic ),
            new AuthorListEntry( "evm" ),
            new AuthorListEntry( "鈴村優" ),
            new AuthorListEntry( "そろそろP" ),
            new AuthorListEntry( "めがね１１０" ),
            new AuthorListEntry( "上総" ),
            new AuthorListEntry( "NOIKE" ),
            new AuthorListEntry( "逃亡者" ),
            new AuthorListEntry(),
            new AuthorListEntry( "translator", FontStyle.Italic ),
            new AuthorListEntry( "E-Avalance" ),
            new AuthorListEntry(),
            new AuthorListEntry( "bugs and suggestions reporters", FontStyle.Italic ),
            new AuthorListEntry( "だんちゃん" ),
            new AuthorListEntry( "灰" ),
            new AuthorListEntry( "sanryo" ),
            new AuthorListEntry( "やなぎがうら" ),
            new AuthorListEntry( "elthy" ),
            new AuthorListEntry( "fyfy" ),
            new AuthorListEntry( "k-roh" ),
            new AuthorListEntry( "さえ" ),
            new AuthorListEntry( "上総" ),
            new AuthorListEntry( "MI" ),
            new AuthorListEntry( "ほとほと" ),
            new AuthorListEntry( "IGASIO" ),
            new AuthorListEntry( "PEX" ),
            new AuthorListEntry(),
            new AuthorListEntry( "and you.", FontStyle.Bold | FontStyle.Italic ),
        };
        private static readonly Pen HILIGHT = new Pen( Color.Gray, 2 );
        private static readonly Pen HILIGHT_EDIT = new Pen( Color.Red, 2 );
        private static readonly Color REPEAT_AREA = Color.FromArgb( 105, 139, 105 );
        private static readonly Pen _PEN_123_123_123 = new Pen( Color.FromArgb( 123, 123, 123 ) );
        private static readonly SolidBrush _BRS_TRACKBG_ODD = new SolidBrush( Color.FromArgb( 240, 240, 240 ) );
        private static readonly SolidBrush _BRS_TRACKBG_EVEN = new SolidBrush( Color.FromArgb( 212, 212, 212 ) );
        private static readonly SolidBrush _BRS_TRACK_NAME = new SolidBrush( Color.FromArgb( 80, 80, 80 ) );
        private static readonly Pen _PEN_BOUNDS = new Pen( new HatchBrush( HatchStyle.Percent50, Color.Black, Color.White ), 4 );
        private static readonly Pen _PEN_FIXED_BOUNDS = new Pen( new HatchBrush( HatchStyle.Percent50, Color.Red, Color.White ), 4 );
        #endregion

        #region Static Field
        //private static Color CANVAS_BACKGROUND_HILIGHT = Color.Black;
        #endregion

        #region Field
        /// <summary>
        /// ファイルには保存されていたが、現在の環境では使えないプラグインのトラック情報。
        /// 読込時に判定して作成し、保存時には一応保存する。
        /// </summary>
        private List<TimeTable> m_not_used_plugin = new List<TimeTable>();
        private List<PluginConfig> m_not_used_plugin_config = new List<PluginConfig>();
        /// <summary>
        /// 変更可能な設定値 
        /// </summary>
        //private EnvSettings AppManager.Config = new EnvSettings();
        private Color TRIANGLE_COLOR = Color.SteelBlue;
        /// <summary>
        /// pictureBox1上のマウスの位置
        /// </summary>
        private Point m_mousePosition;
        /// <summary>
        /// pictureBox1上のクリックされたアイテムの場所
        /// </summary>
        private Item m_clicked;
        private Rectangle m_rcHilight;
        /// <summary>
        /// エントリの編集モードで、マウスカーソルを変更するべきエリア
        /// </summary>
        private Rectangle m_editHandleLeft = new Rectangle();
        private Rectangle m_editHandleRight = new Rectangle();
        private Item m_edit_handle_ed_item;
        private string m_filePath = "";
        private int m_startToDrawX = 0;
        private int m_startToDrawY = 0;
        private PointF m_expandRange;
        private bool m_initialized = false;
        //private bool m_edited = false;
        /// <summary>
        /// コピーされたタイムテーブル
        /// </summary>
        private TimeTable m_copied_timetable = null;
        private Color TOOL_COLOR = Color.DarkGray;
        /// <summary>
        /// トラック上のドラッグによりエントリを追加するもーど中に保持される、もともとのタイムテーブルグループのキャッシュ
        /// </summary>
        private TimeTableGroup m_editing_group;
        /// <summary>
        /// ドラッグ中のアイテム
        /// </summary>
        private Item m_dragging;
        private float m_editing_t1, m_editing_t2;
        private TimeTableEntry m_copied_entry = null;
        private Telop m_copied_telop = null;
        private Item m_copied;
        private EditMode m_edit_mode = EditMode.None;
        /// <summary>
        /// ドラッグによりエントリをスライドするモードで、スライド開始前の、エントリのもともとのbegin時刻
        /// </summary>
        private TimeTableEntry m_slide_original = null;
        private bool m_slide_moved = false;
        //private float m_total_memory = 0f;
#if DEBUG
        private long m_counter = 0L;
#endif
        private DateTime m_preview_time;
        private VersionInfo m_version_form = null;

        private bool m_avi_writing = false;
        private Keys m_last_key = Keys.None;
        private int m_realtime_group = 0;
        private int m_realtime_track;
        private int m_realtime_entry;
        private DisplacementControl m_curve;
        private bool m_is_repeat_mode = false;
        /// <summary>
        /// Paintイベントをスキップする必要のある時true
        /// </summary>
        private bool m_skip_paint = false;
        /// <summary>
        /// クオンタイズする際のグリッド時刻のリスト。スクロールバーが移動した時、更新
        /// </summary>
        private float[] m_grids;
        /// <summary>
        /// VSQトラックを固定表示する場合の、VSQトラック表示部分の高さ
        /// </summary>
        private int m_vsq_height = 0;
        private FormPreview m_form_preview;
        bool m_avi_cancel = false;
        Thread m_stdout;
        Process m_ffmpeg;
        Process m_mencoder;
        //bool m_is_rawmode = false;
        private int m_current_frame = 0;
        private MediaPlayer m_player;
        private ZorderItem m_editing_item = null;
        private EditingBounds m_editing = new EditingBounds();
        /// <summary>
        /// 最初画像がクリックされた位置の、画像座標系での位置
        /// </summary>
        private Point m_base_point;
        /// <summary>
        /// 画像がクリックされた時点での、その画像の位置設定情報
        /// </summary>
        private Point m_init_position;
        /// <summary>
        /// テキストエディットモード
        /// </summary>
        bool m_text_edit = false;
        /// <summary>
        /// 編集中のテキスト
        /// </summary>
        TextBox m_text = null;
        /// <summary>
        /// オリジナルのテキスト
        /// </summary>
        string m_text_original;
        /// <summary>
        /// 編集しているテキストのID
        /// </summary>
        int m_text_id;
        double[] m_buf = new double[BUF_LEN];
        double m_fps;
        DateTime m_last_ignitted = new DateTime();
        private DateTime m_started_date;
        private Thread m_preview_thread = null;
        private BSplitContainer m_panels;
        private Telop m_editing_telop_original = null;
        #endregion

        private delegate void ChangeTitleTextDelegate( string encoder_type, int percent, int current_frame, int max_frames );
        private delegate void ForceScreenUpdateDelegate();
        private delegate void Form1_AviWritingChange( bool value );

        public Form1( string file ) {
            AppManager.SaveData = new SettingsEx();
            m_filePath = file;
            InitializeComponent();

            m_panels = new BSplitContainer();

            // m_panels
            m_panels.Name = "m_panels";
            m_panels.Orientation = Orientation.Vertical;
            m_panels.Panel1.BorderColor = SystemColors.ControlDark;
            m_panels.Panel1.BorderStyle = BorderStyle.FixedSingle;
            m_panels.Panel2.BorderColor = SystemColors.ControlDark;
            m_panels.Panel2.BorderStyle = BorderStyle.FixedSingle;
            m_panels.FixedPanel = FixedPanel.Panel1;
            m_panels.Panel1.Controls.Add( previewer );
            m_panels.Panel2.Controls.AddRange( new Control[]{ side,
                                                              pictureBox1,
                                                              hScrollBar1,
                                                              vScrollBar1,
                                                              pictureBox2,
                                                              preview_image } );
            m_panels.Panel1MinSize = 0;
            m_panels.Panel2.SizeChanged += new EventHandler( Panel2_SizeChanged );
            m_container.FixedPanel = FixedPanel.Panel1;
            m_container.Panel1.Controls.Add( property );
            m_container.Panel2.Controls.Add( m_panels );
            m_panels.Dock = DockStyle.Fill;
            property.Dock = DockStyle.Fill;
            previewer.Dock = DockStyle.Fill;

            this.pictureBox1.MouseWheel += new MouseEventHandler( pictureBox1_MouseWheel );
            m_player = new MediaPlayer();
            previewer.TrackVolumeValue = m_player.Volume;
            Messaging.LoadMessages();
            LoadConfig();
            this.SizeChanged += new EventHandler( Form1_LocationOrSizeChanged );
            this.LocationChanged += new EventHandler( Form1_LocationOrSizeChanged );
            AppManager.EditedChanged += new EventHandler( AppManager_EditedChanged );
            m_form_preview = new FormPreview();
            m_form_preview.FormClosing += new FormClosingEventHandler( m_form_preview_FormClosing );
            m_curve = new DisplacementControl();
            m_curve.FormClosing += new FormClosingEventHandler( m_curve_FormClosing );
            menuVisualVsqTrack.Checked = AppManager.Config.FixVsqTrackPosition;
            ApplyLanguage();
        }

        private void m_curve_FormClosing( object sender, FormClosingEventArgs e ) {
            e.Cancel = true;
            menuVisualTransform.Checked = false;
        }

        private void AppManager_EditedChanged( object sender, EventArgs e ) {
            UpdateFormTitle();
            UpdateObjectList();
            menuEditRedo.Enabled = AppManager.IsRedoAvailable; //ExecuteとResiterが離れているので，ここで更新する必要がある
            menuEditUndo.Enabled = AppManager.IsUndoAvailable;
            if ( AppManager.Edited ) {
                this.Invalidate();
            }
        }

        private void Panel2_SizeChanged( object sender, EventArgs e ) {
            ResizePanel2();
        }

        private void m_form_preview_FormClosing( object sender, FormClosingEventArgs e ) {
            e.Cancel = true;
            m_form_preview.Hide();
            previewer.Parent = m_panels.Panel1;
            int total_height = m_panels.Panel1.Height + m_panels.Panel2.Height;
            int new_distance = (int)(total_height * AppManager.Config.LastPreviewAspecto);
            m_panels.SplitterDistance = new_distance;
            m_panels.IsSplitterFixed = false;
            menuVisualPreviewSeparate.Checked = false;
        }

        #region property
        private void property_TelopDeleting( ZorderItem e ) {
#if DEBUG
            Common.DebugWriteLine( "property1_TelopDeleting" );
            Common.DebugWriteLine( "    e.Type=" + e.Type );
#endif
            if ( e.Type == ZorderItemType.telop ) {
                Command run = Command.GCommandDeleteTelop( AppManager.SaveData[e.Index] );
                AppManager.Register( AppManager.SaveData.Execute( run ) );
                Telop.DecideLane( AppManager.SaveData.m_telop_ex2 );
                property.Editing = null;
                if ( m_curve.comboObjects.SelectedItem != null ){
                    TagForTreeNode t = (TagForTreeNode)m_curve.comboObjects.SelectedItem;
                    if ( t.type == ZorderItemType.telop && t.id_or_index == e.Index ) {
                        m_curve.SetSelectedNone();
                    }
                }
                SetVScrollRange();
            }
        }

        private void property_EditingItemChanged( ZorderItem item ) {
#if DEBUG
            Common.DebugWriteLine( "property1_EditingItemChanged" );
#endif
            if ( item != null ) {
                switch ( item.Type ) {
                    case ZorderItemType.another:
                        property.SelectedObject = AppManager.SaveData.m_group_another[item.Index].Clone();
                        break;
                    case ZorderItemType.character:
                        property.SelectedObject = AppManager.SaveData.m_groups_character[item.Index].Clone();
                        break;
                    case ZorderItemType.telop:
                        //Telop.DecideLane( AppManager.SaveData.m_telop_ex2 );
                        property.SelectedObject = AppManager.SaveData[item.Index].Clone();
                        break;
                }
            } else {
                property.SelectedObject = null;
            }
        }

        private void property_TelopAdding() {
            h_addTelop( this, new EventArgs() );
        }

        private void property_PropertyValueChanged( object sender, PropertyValueChangedEventArgs e ) {
#if DEBUG
            Common.DebugWriteLine( "property1_PropertyValueChanged(object,PropertyValueChangedEventArgs)" );
#endif
            int target = property.Editing.Index;
            string start = "";
            string type = "";
            string name = "";

#if DEBUG
            Common.DebugWriteLine( "    (property1.SelectedObject is TimeTable)     =" + (property.SelectedObject is TimeTable) );
            Common.DebugWriteLine( "    (property1.SelectedObject is TimeTableGroup)=" + (property.SelectedObject is TimeTableGroup) );
            Common.DebugWriteLine( "    (property1.SelectedObject is Telop)         =" + (property.SelectedObject is Telop) );
#endif
            // property1.SelectedObjectは，それぞれの編集対象の単なるクローンなので，
            // 変更されたらCommandを使って本体を更新する必要がある
            if ( property.SelectedObject is TimeTable ) {
                Command run = Command.GCommandEditTimeTable( TimeTableType.another, -1, target, (TimeTable)property.SelectedObject );
                AppManager.Register( AppManager.SaveData.Execute( run ) );
                start = AppManager.SaveData[TimeTableType.another, -1].GetFirstOn( target ) + "";
                type = "another";
                name = AppManager.SaveData[TimeTableType.another, -1][target].Text;
            } else if ( property.SelectedObject is TimeTableGroup ) {
                Command run = Command.GCommandEditGroup( TimeTableType.character, target, (TimeTableGroup)property.SelectedObject );
                AppManager.Register( AppManager.SaveData.Execute( run ) );
                start = "" + AppManager.SaveData[TimeTableType.character, target].GetFirstOn();
                type = "character";
                name = AppManager.SaveData[TimeTableType.character, target].Text;
            } else if ( property.SelectedObject is Telop ) {
                Command run = Command.GCommandEditTelop( target, (Telop)property.SelectedObject );
                AppManager.Register( AppManager.SaveData.Execute( run ) );
                start = "" + AppManager.SaveData[target].Start;
                type = "telop";
                name = AppManager.SaveData[target].Text;
            }

            // property1.ListViewの表示内容を更新
            ZorderItem editing = property.Editing;
#if DEBUG
            Common.DebugWriteLine( "    editing.Type=" + editing.Type );
            Common.DebugWriteLine( "    editing.Index=" + editing.Index );
            Common.DebugWriteLine( "    editing.Name=" + editing.Name );
            bool found = false;
#endif
            foreach ( ListViewItem item in property.ListView.Items ) {
                if ( item.Tag is ZorderItem ) {
                    ZorderItem zitem = (ZorderItem)item.Tag;
                    if ( zitem.Type == editing.Type && zitem.Index == editing.Index ) {
                        item.SubItems[0].Text = start;
                        item.SubItems[1].Text = type;
                        item.SubItems[2].Text = name;
#if DEBUG
                        found = true;
#endif
                        break;
                    }
                }
            }

#if DEBUG
            Common.DebugWriteLine( "found=" + found );
#endif
            UpdateEditHandle();
            AppManager.Edited = true;
        }
        #endregion

        #region hScrollBar1
        private void hScrollBar1_Scroll( object sender, ScrollEventArgs e ) {
            m_startToDrawX = StartToDrawX();
            UpdateGridList();
            pictureBox1.Invalidate();
        }
        #endregion

        private void vScrollBar1_Scroll( object sender, ScrollEventArgs e ) {
            m_startToDrawY = StartToDrawY();
            side.Refresh();
            pictureBox1.Refresh();
        }

        #region pictureBox1
        private void pictureBox1_MouseWheel( object sender, MouseEventArgs e ) {
            if ( (Control.ModifierKeys & Keys.Shift) == Keys.Shift ) {
                if ( vScrollBar1.Enabled ) {
                    int prev = vScrollBar1.Value;
                    float add = -(float)e.Delta / AppManager.Config.WheelRatio;
                    int set = (int)((float)prev + add);
                    if ( set > vScrollBar1.Maximum + 1 - vScrollBar1.LargeChange ) {
                        set = vScrollBar1.Maximum + 1 - vScrollBar1.LargeChange;
                    } else if ( set < vScrollBar1.Minimum ) {
                        set = vScrollBar1.Minimum;
                    }
                    if ( prev != set ) {
                        vScrollBar1.Value = set;
                        m_startToDrawY = StartToDrawY();
                        pictureBox1.Invalidate();
                        side.Invalidate();
                    }
                }
            } else {
                if ( hScrollBar1.Enabled ) {
                    int prev = hScrollBar1.Value;
                    float add = -(float)e.Delta / AppManager.Config.WheelRatio;
                    int set = (int)((float)prev + add);
                    if ( set > hScrollBar1.Maximum + 1 - hScrollBar1.LargeChange ) {
                        set = hScrollBar1.Maximum + 1 - hScrollBar1.LargeChange;
                    } else if ( set < hScrollBar1.Minimum ) {
                        set = hScrollBar1.Minimum;
                    }
                    if ( prev != set ) {
                        hScrollBar1.Value = set;
                        m_startToDrawX = StartToDrawX();
                        pictureBox1.Invalidate();
                    }
                    UpdateGridList();
                }
            }
        }

        private void pictureBox1_PreviewKeyDown( object sender, PreviewKeyDownEventArgs e ) {
            if ( e.KeyCode == Keys.Delete ) {
                DeleteEntry();
            }
            if ( AppManager.Playing && menuEditRealTime.Checked ) {
                if ( m_last_key == e.KeyCode ) {
                    return;
                }
                string target = "";
                float m_end = Now;
                switch ( e.KeyCode ) {
                    case Keys.A:
                        target = "a";
                        break;
                    case Keys.I:
                        target = "i";
                        break;
                    case Keys.U:
                        target = "u";
                        break;
                    case Keys.E:
                        target = "e";
                        break;
                    case Keys.O:
                        target = "o";
                        break;
                    case Keys.Space:
                        if ( m_last_key != Keys.None ) {
                            TimeTableEntry tte = (TimeTableEntry)AppManager.SaveData.m_groups_character[m_realtime_group][m_realtime_track][m_realtime_entry].Clone();
                            tte.end = m_end;
                            AppManager.SaveData.m_groups_character[m_realtime_group][m_realtime_track][m_realtime_entry].end = m_end;
                            AppManager.SaveData.m_groups_character[m_realtime_group][m_realtime_track].RemoveAt( m_realtime_entry );
                            Command run = Command.GCommandAddTimeTableEntry( TimeTableType.character,
                                                                             m_realtime_group,
                                                                             m_realtime_track,
                                                                             tte );
                            AppManager.Register( AppManager.SaveData.Execute( run ) );
                        }
                        m_last_key = Keys.None;
                        return;
                    default:
                        return;
                }
                //まず、直前に入力されたエントリを終了させる処理
                if ( m_last_key != Keys.None ) {
                    TimeTableEntry tte = (TimeTableEntry)AppManager.SaveData.m_groups_character[m_realtime_group][m_realtime_track][m_realtime_entry].Clone();
                    tte.end = m_end;
                    AppManager.SaveData.m_groups_character[m_realtime_group][m_realtime_track].RemoveAt( m_realtime_entry );
                    Command run = Command.GCommandAddTimeTableEntry( TimeTableType.character,
                                                                     m_realtime_group,
                                                                     m_realtime_track,
                                                                     tte );
                    AppManager.Register( AppManager.SaveData.Execute( run ) );
                }
                //今しがた押されたキーに対応するエントリを追加。
                for ( int i = 0; i < AppManager.SaveData.m_groups_character[m_realtime_group].Count; i++ ) {
                    if ( AppManager.SaveData.m_groups_character[m_realtime_group][i].Text == target ) {
                        m_realtime_track = i;
                        break;
                    }
                }
                AppManager.SaveData.m_groups_character[m_realtime_group][m_realtime_track].Add( new TimeTableEntry( m_end, m_end, target ) );
                AppManager.SaveData.m_groups_character[m_realtime_group][m_realtime_track].Sort();
                //sortしたのでm_realtime_entryを検索で探す
                for ( int entry = 0; entry < AppManager.SaveData.m_groups_character[m_realtime_group][m_realtime_track].Count; entry++ ) {
                    if ( AppManager.SaveData.m_groups_character[m_realtime_group][m_realtime_track][entry].begin == m_end ) {
                        m_realtime_entry = entry;
                        break;
                    }
                }
                m_last_key = e.KeyCode;
            }
        }

        private void pictureBox1_MouseClick( object sender, MouseEventArgs e ) {
            m_mousePosition.X = e.X;
            m_mousePosition.Y = e.Y;

            if ( e.Button == MouseButtons.Right ) {
                if ( 0 <= e.Y && e.Y <= AppManager.Config.TrackHeight ) {
                    cmenuRepeat.Show( pictureBox1, e.X, e.Y );
                    return;
                }
            }

            if ( m_edit_mode == EditMode.Dragging ) {
                return;
            }

            if ( m_edit_mode == EditMode.Sliding ) {
                if ( m_slide_moved ) {
                    return;
                }
                m_edit_mode = EditMode.None;
            }

            if ( m_edit_mode == EditMode.Selected ) {
                if ( e.Button == MouseButtons.Right ) {
                    m_edit_mode = EditMode.None;
                }
            }

            if ( m_edit_mode == EditMode.None/*!m_editMode*/ ) {
                m_clicked = GetGroupItem( m_mousePosition.X + m_startToDrawX, m_mousePosition.Y + m_startToDrawY );
                if ( e.Button == MouseButtons.Right ) {
                    #region 右クリック
                    m_edit_mode = EditMode.None;
                    int group = m_clicked.group;
                    int track = m_clicked.track;
                    int entry = m_clicked.entry;

                    if ( !cmenu.IsDisposed || cmenu != null ) {
                        cmenu.Dispose();
                    }
                    cmenu = new ContextMenuStrip();
                    cmenu.RenderMode = ToolStripRenderMode.ManagerRenderMode;
                    cmenu.ShowCheckMargin = false;
                    cmenu.ShowImageMargin = false;
                    cmenu.Font = AppManager.Config.Font.GetFont();

                    if ( m_clicked.type == TimeTableType.top ) {
                        return;
                    }
                    if ( group < 0 ) {
                        cmenu.Items.Add( _( "Video size configuration" ),
                                         null,
                                         new EventHandler( h_setVideoSize ) );
                    } else {
                        if ( track < 0 ) {
                            #region タイトルがクリックされたとき
                            switch ( m_clicked.type ) {
                                case TimeTableType.vsq:
                                    cmenu.Items.Add( _( "Read from VSQ file" ), null, new EventHandler( h_readVsq ) );
                                    break;
                                case TimeTableType.character:
                                    if ( AppManager.SaveData.m_groups_character[group].Character != null ) {
                                        cmenu.Items.Add( _( "Edit character" ), null, new EventHandler( h_editCharacter ) );
                                        if ( AppManager.SaveData.m_groups_character[group].Character.Type == CharacterType.def ) {
                                            cmenu.Items.Add( "-" );
                                            cmenu.Items.Add( _( "Preview image" ), null, new EventHandler( h_previewImage ) );
                                            cmenu.Items.Add( _( "Image placement" ), null, new EventHandler( h_setImagePosition ) );
                                            cmenu.Items.Add( _( "Scale setting" ), null, new EventHandler( h_setScale ) );
                                            cmenu.Items.Add( "-" );
                                            cmenu.Items.Add( _( "Generate wink" ), null, new EventHandler( h_addWink ) );
                                        }
                                    }
                                    cmenu.Items.Add( "-" );
                                    cmenu.Items.Add( _( "Delete" ), null, new EventHandler( h_deleteTrack ) );
                                    break;
                                case TimeTableType.telop:
                                    cmenu.Items.Add( _( "Add Telop" ), null, new EventHandler( h_addTelop ) );
                                    break;
                                case TimeTableType.another:
                                    cmenu.Items.Add( _( "Add track" ), null, new EventHandler( h_addTrack ) );
                                    break;
                            }
                            #endregion
                        } else {
                            bool copy_enabled = true;
                            if ( entry < 0 ) {
                                #region トラックがクリックされたとき
                                switch ( m_clicked.type ) {
                                    case TimeTableType.vsq:
                                        cmenu.Items.Add( _( "Generate Lipsync from this track" ), null, new EventHandler( h_genMouthFromVsq ) );
                                        if ( AppManager.SaveData.m_group_vsq[track].Count == 0 ) {
                                            copy_enabled = false;
                                        }
                                        break;
                                    case TimeTableType.character:
                                        cmenu.Items.Add( _( "Note ON from here" ) + "(&O)",
                                                         null,
                                                         new EventHandler( h_noteON ) );
                                        cmenu.Items.Add( _( "Preview image" ),
                                                         null,
                                                         new EventHandler( h_previewImage ) );
                                        if ( AppManager.SaveData.m_groups_character[group][track].Count == 0 ) {
                                            copy_enabled = false;
                                        }
                                        break;
                                    case TimeTableType.another:
                                        cmenu.Items.Add( _( "Note ON from here" ) + "(&O)",
                                                         null,
                                                         new EventHandler( h_noteON ) );
                                        if ( AppManager.SaveData.m_group_another[track].Image == null ) {
                                            cmenu.Items.Add( _( "Set image" ),
                                                             null,
                                                             new EventHandler( h_setImage ) );
                                        } else {
                                            cmenu.Items.Add( _( "Preview image" ),
                                                             null,
                                                             new EventHandler( h_previewImage ) );
                                            cmenu.Items.Add( _( "Change image" ),
                                                             null,
                                                             new EventHandler( h_setImage ) );
                                        }
                                        ToolStripMenuItem mItemImage = new ToolStripMenuItem( _( "Image" ) );
                                        mItemImage.DropDown = new ContextMenuStrip();
                                        ((ContextMenuStrip)mItemImage.DropDown).Items.Add( _( "Image placement" ),
                                                                                           null,
                                                                                           new EventHandler( h_setImagePosition ) );
                                        ((ContextMenuStrip)mItemImage.DropDown).Items.Add( _( "Scale setting" ),
                                                                                           null,
                                                                                           new EventHandler( h_setScale ) );
                                        ((ContextMenuStrip)mItemImage.DropDown).ShowCheckMargin = false;
                                        ((ContextMenuStrip)mItemImage.DropDown).ShowImageMargin = false;
                                        cmenu.Items.Add( mItemImage );
                                        if ( AppManager.SaveData.m_group_another[track].Count == 0 ) {
                                            copy_enabled = false;
                                        }
                                        break;
                                    case TimeTableType.plugin:
                                        cmenu.Items.Add( _( "Note ON from here" ) + "(&O)",
                                                         null,
                                                         new EventHandler( h_noteON ) );
                                        if ( AppManager.SaveData.m_group_plugin[track].Count == 0 ) {
                                            copy_enabled = false;
                                        }
                                        break;
                                }

                                //エントリの貼付け
                                if ( m_clicked.type != TimeTableType.vsq ) {
                                    cmenu.Items.Add( _( "Paste" ) + "(&V)",
                                                     null,
                                                     new EventHandler( h_pasteEntry ) );
                                    if ( m_copied_entry == null && m_copied_telop == null ) {
                                        cmenu.Items[cmenu.Items.Count - 1].Enabled = false;
                                    }
                                }


                                #endregion
                            } else {
                                #region エントリがクリックされたとき
                                copy_enabled = true;//エントリがクリックされたので、エントリの個数は1個以上！
                                if ( m_clicked.type == TimeTableType.vsq ) {
                                    cmenu.Items.Add( _( "Generate Lipsync from this track" ), null, new EventHandler( h_genMouthFromVsq ) );
                                } else {
                                    cmenu.Items.Add( _( "Note OFF" ) + "(&O)", null, new EventHandler( h_noteOFF ) );
                                    if ( m_clicked.type == TimeTableType.character ) {
                                        cmenu.Items.Add( _( "Image Preview" ), null, new EventHandler( h_previewImage ) );
                                    }
                                    cmenu.Items.Add( _( "Numeric Entry" ) + "(&N)", null, new EventHandler( h_editEntry ) );
                                    if ( m_clicked.type != TimeTableType.telop ) {
                                        cmenu.Items.Add( _( "Expand" ) + "(&E)", null, new EventHandler( h_expandEntry ) );
                                    }
                                    cmenu.Items.Add( "-" );

                                    // グループ固有の機能
                                    if ( m_clicked.type == TimeTableType.another ) {
                                        if ( AppManager.SaveData.m_group_another[track].Image == null ) {
                                            //if ( s.m_group_another[track].GetImage( 0f ) == null ) {
                                            cmenu.Items.Add( _( "Set Image" ), null, new EventHandler( h_setImage ) );
                                        } else {
                                            cmenu.Items.Add( _( "Preview Image" ), null, new EventHandler( h_previewImage ) );
                                            cmenu.Items.Add( _( "Change Image" ), null, new EventHandler( h_setImage ) );
                                        }
                                        ToolStripMenuItem mItemImage = new ToolStripMenuItem( _( "Image" ) );
                                        mItemImage.DropDown = new ContextMenuStrip();
                                        ((ContextMenuStrip)mItemImage.DropDown).Items.Add( _( "Image placement" ),
                                                                                           null,
                                                                                           new EventHandler( h_setImagePosition ) );
                                        ((ContextMenuStrip)mItemImage.DropDown).Items.Add( _( "Scale setting" ),
                                                                                           null,
                                                                                           new EventHandler( h_setScale ) );
                                        ((ContextMenuStrip)mItemImage.DropDown).ShowCheckMargin = false;
                                        ((ContextMenuStrip)mItemImage.DropDown).ShowImageMargin = false;
                                        cmenu.Items.Add( mItemImage );
                                        cmenu.Items.Add( "-" );
                                    } else if ( m_clicked.type == TimeTableType.plugin ) {
                                        if ( (AppManager.SaveData.m_plugins[m_clicked.track].Instance.Type & Constants.LS_ENABLES_ENTRY_SETTING) == Constants.LS_ENABLES_ENTRY_SETTING ) {
                                            cmenu.Items.Add( _( "Plugin config. of this entry" ), null, new EventHandler( h_entrySetting ) );
                                            cmenu.Items.Add( "-" );
                                        }
                                    }

                                    //編集系の共通コマンド
                                    cmenu.Items.Add( _( "Copy" ) + "(&C)", null, new EventHandler( h_copyEntry ) );
                                    cmenu.Items.Add( _( "Cut" ) + "(&X)", null, new EventHandler( h_cutEntry ) );
                                    cmenu.Items.Add( _( "Split Entry" ) + "(&S)", null, new EventHandler( h_splitEntry ) );
                                }
                                #endregion
                            }

                            #region タイムライン用の共通コマンド
                            //タイムライン
                            if ( m_clicked.type != TimeTableType.telop ) {
                                ToolStripMenuItem mItemTimeline = new ToolStripMenuItem( _( "Timeline" ) );
                                ContextMenuStrip cItemTimeline = new ContextMenuStrip();
                                cItemTimeline.Items.Add( _( "Copy" ), null, new EventHandler( h_copyTimeTable ) );
                                if ( !copy_enabled ) {
                                    cItemTimeline.Items[cItemTimeline.Items.Count - 1].Enabled = false;
                                }
                                cItemTimeline.Items.Add( _( "Copy On/Off inverted" ), null, new EventHandler( h_copyTimeTableInvert ) );
                                if ( !copy_enabled ) {
                                    cItemTimeline.Items[cItemTimeline.Items.Count - 1].Enabled = false;
                                }
                                cItemTimeline.Items.Add( _( "Paste" ), null, new EventHandler( h_pasteTimeTable ) );
                                if ( m_copied_timetable == null ) {
                                    cItemTimeline.Items[cItemTimeline.Items.Count - 1].Enabled = false;
                                }
                                cItemTimeline.Items.Add( _( "Import from TEXT" ), null, new EventHandler( h_importFromText ) );
                                cItemTimeline.Items.Add( _( "Export to TEXT" ), null, new EventHandler( h_exportToText ) );
                                cItemTimeline.ShowCheckMargin = false;
                                cItemTimeline.ShowImageMargin = false;
                                mItemTimeline.DropDown = cItemTimeline;
                                cmenu.Items.Add( mItemTimeline );
                            }

                            //編集
                            ToolStripMenuItem mItemEdit = new ToolStripMenuItem( _( "Edit" ) );
                            ContextMenuStrip cItemEdit = new ContextMenuStrip();
                            if ( m_clicked.type != TimeTableType.plugin && m_clicked.type != TimeTableType.character && m_clicked.type != TimeTableType.telop ) {
                                cItemEdit.Items.Add( _( "Delete" ), null, new EventHandler( h_deleteTrack ) );
                            }
                            cItemEdit.Items.Add( _( "Delete entries" ), null, new EventHandler( h_clearEntry ) );
                            if ( !copy_enabled ) {
                                cItemEdit.Items[cItemEdit.Items.Count - 1].Enabled = false;
                            }
                            cItemEdit.Items.Add( _( "Shift this time-line" ), null, new EventHandler( h_shiftEntries ) );
                            if ( !copy_enabled ) {
                                cItemEdit.Items[cItemEdit.Items.Count - 1].Enabled = false;
                            }
                            cItemEdit.ShowCheckMargin = false;
                            cItemEdit.ShowImageMargin = false;
                            mItemEdit.DropDown = cItemEdit;
                            cmenu.Items.Add( mItemEdit );

                            #endregion

                        }
                    }
                    if ( cmenu.Items.Count >= 1 ) {
                        cmenu.Show( pictureBox1, new Point( e.X, e.Y ) );
                    }
                    #endregion
                } else if ( e.Button == MouseButtons.Left ) {
                    #region 左クリック
                    if ( m_clicked.entry >= 0 ) {
                        m_edit_handle_ed_item = GetGroupItem( e.X + m_startToDrawX, e.Y + m_startToDrawY );
#if DEBUG
                        Common.DebugWriteLine( "pictureBox1_MouseClick; m_edit_handle_ed_item.entry=" + m_edit_handle_ed_item.entry );
#endif
                        UpdateEditHandle( e.X, e.Y );
                        m_edit_mode = EditMode.Selected;
                        float time = SecFromXCoord( e.X );
                        UpdateExpandRange( time );
                        if ( m_clicked.type == TimeTableType.telop ) {
                            Telop selected = AppManager.SaveData[m_clicked.entry];
                            property.Editing = new ZorderItem( selected.Text, ZorderItemType.telop, selected.ID );
                        }
                        pictureBox1.Invalidate();
                    }
                    #endregion
                }
            } else if ( m_edit_mode != EditMode.EditingLeft && m_edit_mode != EditMode.EditingRight/* !m_editEntry*/ ) {
                m_clicked = GetGroupItem( e.X + m_startToDrawX, e.Y + m_startToDrawY );
                if ( m_clicked.entry >= 0 ) {
                    UpdateEditHandle( e.X, e.Y );
                    float time = SecFromXCoord( e.X );
                    UpdateExpandRange( time );
                    if ( m_clicked.type == TimeTableType.telop ) {
                        Telop selected = AppManager.SaveData[m_clicked.entry];
                        property.Editing = new ZorderItem( selected.Text, ZorderItemType.telop, selected.ID );
                    }
                    pictureBox1.Invalidate();
                } else {
                    m_edit_mode = EditMode.None;
                }
            }
        }

        private void pictureBox1_MouseMove( object sender, MouseEventArgs e ) {
            if ( AppManager.Playing ) {
                m_mousePosition = e.Location;
                return;
            }

            Rectangle last = m_rcHilight;
            m_rcHilight = GetHilightRect( m_mousePosition.X, m_mousePosition.Y );

            if ( preview_image.Visible ) {
                TimeSpan ts = DateTime.Now.Subtract( m_preview_time );
                if ( ts.TotalMilliseconds > 1000 ) {
                    preview_image.Visible = false;
                }
            }

            statusTime.Text = SecFromXCoord( e.X ).ToString( "0.00" ) + " sec";
            if ( m_edit_mode != EditMode.Selected ) {
                m_mousePosition.X = e.X;
                m_mousePosition.Y = e.Y;
                if ( m_edit_mode == EditMode.Dragging ) {
                    // エントリを追加するモード
                    m_editing_t2 = SecFromXCoord( e.X );
                    m_slide_moved = true;
                    if ( AppManager.Config.QuantizeMode != QuantizeMode.off && m_grids != null ) {
                        m_editing_t2 = GetSnapPoint( m_editing_t2 );
                    }
                    float begin = m_editing_t1;
                    float end = m_editing_t2;
                    if ( begin > end ) {
                        float b = begin;
                        begin = end;
                        end = b;
                    }
                    if ( begin < 0f ) {
                        begin = 0f;
                    }
                    if ( AppManager.SaveData.m_totalSec < end ) {
                        end = AppManager.SaveData.m_totalSec;
                    }
                    if ( m_dragging.type == TimeTableType.telop ) {
                        AppManager.SaveData[m_editing_telop_original.ID].Start = begin;
                        AppManager.SaveData[m_editing_telop_original.ID].End = end;
                    } else if ( m_dragging.type != TimeTableType.vsq ) {
                        AppManager.SaveData[m_dragging.type, m_dragging.group] = null;
                        AppManager.SaveData[m_dragging.type, m_dragging.group] = (TimeTableGroup)m_editing_group.Clone();
                        AppManager.SaveData[m_dragging.type, m_dragging.group].Interrup( m_dragging.track, begin, end );
                    }
                    pictureBox1.Cursor = Cursors.Arrow;
                } else if ( m_edit_mode == EditMode.Sliding ) {
                    // エントリをドラッグしてスライドさせるモード
                    m_slide_moved = true;
                    m_editing_t2 = SecFromXCoord( e.X );
                    int group = m_dragging.group;
                    int track = m_dragging.track;
                    int entry = m_dragging.entry;
                    float diff = (m_editing_t2 - m_editing_t1);
                    float original_begin;
                    if ( m_dragging.type == TimeTableType.telop ) {
                        original_begin = m_editing_telop_original.Start;
                    } else {
                        original_begin = m_slide_original.begin;
                    }
                    float begin = original_begin + diff;

                    if ( AppManager.Config.QuantizeMode != QuantizeMode.off && m_grids != null ) {
                        begin = GetSnapPoint( begin );
                        diff = begin - original_begin;
                    }
                    float end = 0;
                    float length = 0;

                    if ( m_dragging.type == TimeTableType.telop ) {
                        end = m_editing_telop_original.End + diff;
                        length = m_editing_telop_original.Length;
                    } else if ( m_dragging.type != TimeTableType.vsq ) {
                        end = AppManager.SaveData[m_dragging.type, group][track][entry].end + diff;
                        length = AppManager.SaveData[m_dragging.type, group][track][entry].Length;
                        if ( begin < m_expandRange.X ) {
                            begin = m_expandRange.X;
                            end = begin + length;
                        } else {
                            if ( m_expandRange.Y < end ) {
                                end = m_expandRange.Y;
                                begin = end - length;
                            } else {
                                end = begin + length;
                            }
                        }
                    }

                    int ibegin = XCoordFromSec( begin );
                    int y = m_dragging.row_index * AppManager.Config.TrackHeight - m_startToDrawY;
                    int width = (int)(length * AppManager.Config.PixelPerSec);
                    m_rcHilight = new Rectangle( ibegin, y, width, AppManager.Config.TrackHeight );

                    if ( m_dragging.type == TimeTableType.telop ) {
                        AppManager.SaveData[m_editing_telop_original.ID].Start = begin;
                        AppManager.SaveData[m_editing_telop_original.ID].End = end;
                    } else if ( m_dragging.type != TimeTableType.vsq ) {
                        AppManager.SaveData[m_dragging.type, group][track][entry].begin = begin;
                        AppManager.SaveData[m_dragging.type, group][track][entry].end = end;
                    }
                    pictureBox1.Cursor = Cursors.Arrow;
                } else if ( m_edit_mode == EditMode.EditingLeft || m_edit_mode == EditMode.EditingRight ) {
                    TimeTableType type = m_edit_handle_ed_item.type;
                    if ( type != TimeTableType.vsq ) {
                        int group = m_edit_handle_ed_item.group;
                        int track = m_edit_handle_ed_item.track;
                        int entry = m_edit_handle_ed_item.entry;
                        if ( entry < 0 ) {
                            m_edit_mode = EditMode.None;
                            return;
                        }
                        float draft_begin, draft_end;
                        if ( type == TimeTableType.telop ) {
                            draft_begin = m_editing_telop_original.Start;
                            draft_end = m_editing_telop_original.End;
                        } else {
                            draft_begin = m_editing_group[track][entry].begin;
                            draft_end = m_editing_group[track][entry].end;
                        }
                        if ( m_edit_mode == EditMode.EditingLeft ) {
                            draft_begin = SecFromXCoord( e.X );
                            if ( AppManager.Config.QuantizeMode != QuantizeMode.off && m_grids != null ) {
                                draft_begin = GetSnapPoint( draft_begin );
                            }
                            if ( draft_begin < 0f ) {
                                draft_begin = 0f;
                            }
                        } else {
                            draft_end = SecFromXCoord( e.X );
                            if ( AppManager.Config.QuantizeMode != QuantizeMode.off && m_grids != null ) {
                                draft_end = GetSnapPoint( draft_end );
                            }
                            if ( AppManager.SaveData.m_totalSec < draft_end ) {
                                draft_end = AppManager.SaveData.m_totalSec;
                            }
                        }
                        if ( draft_begin < draft_end ) {
                            if ( type == TimeTableType.telop ) {
                                AppManager.SaveData[entry].Start = draft_begin;
                                AppManager.SaveData[entry].End = draft_end;
                            } else {
                                AppManager.SaveData[type, group] = null;
                                AppManager.SaveData[type, group] = (TimeTableGroup)m_editing_group.Clone();
                                AppManager.SaveData[type, group][track].RemoveAt( entry );
                                AppManager.SaveData[type, group].Interrup( track, draft_begin, draft_end );
                            }
                        }
                    }
                    pictureBox1.Cursor = Cursors.VSplit;
                }
            } else {
                Point pt = new Point( e.X, e.Y );
                if ( AppManager.IsInRectangle( pt, m_editHandleLeft ) ) {
                    pictureBox1.Cursor = Cursors.VSplit;
                } else if ( AppManager.IsInRectangle( pt, m_editHandleRight ) ) {
                    pictureBox1.Cursor = Cursors.VSplit;
                } else {
                    pictureBox1.Cursor = Cursors.Arrow;
                }
            }
            pictureBox1.Refresh();
        }

        private void pictureBox1_MouseLeave( object sender, EventArgs e ) {
            pictureBox1.Invalidate();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pictureBox1_MouseDown( object sender, MouseEventArgs e ) {
            pictureBox1.Focus();

            m_mousePosition.X = e.X;
            m_mousePosition.Y = e.Y;

            if ( m_edit_mode == EditMode.Selected ) {
                if ( m_edit_handle_ed_item.type == TimeTableType.telop ) {
                    int id = m_edit_handle_ed_item.entry;
                    if ( AppManager.IsInRectangle( e.Location, m_editHandleLeft ) ) {
                        m_editing_telop_original = (Telop)AppManager.SaveData[id].Clone();
                        m_edit_mode = EditMode.EditingLeft;
                    } else if ( AppManager.IsInRectangle( e.Location, m_editHandleRight ) ) {
                        m_editing_telop_original = (Telop)AppManager.SaveData[id].Clone();
                        m_edit_mode = EditMode.EditingRight;
                    }
                } else {
                    if ( AppManager.IsInRectangle( e.Location, m_editHandleLeft ) ) {
                        m_editing_group = null;
                        m_editing_group = (TimeTableGroup)AppManager.SaveData[m_edit_handle_ed_item.type, m_edit_handle_ed_item.group].Clone();
                        m_edit_mode = EditMode.EditingLeft;
                    } else if ( AppManager.IsInRectangle( e.Location, m_editHandleRight ) ) {
                        m_editing_group = null;
                        m_editing_group = (TimeTableGroup)AppManager.SaveData[m_edit_handle_ed_item.type, m_edit_handle_ed_item.group].Clone();
                        m_edit_mode = EditMode.EditingRight;
                    }
                }
#if DEBUG
                Common.DebugWriteLine( "pictureBox1_MouseDown; m_edit_handle_ed_item.entry=" + m_edit_handle_ed_item.entry );
#endif
            } else if ( e.Button == MouseButtons.Left ) {
                m_editing_t1 = SecFromXCoord( e.X );
                if ( AppManager.Config.QuantizeMode != QuantizeMode.off ) {
                    m_editing_t1 = GetSnapPoint( m_editing_t1 );
                }
                m_clicked = GetGroupItem( m_mousePosition.X + m_startToDrawX, m_mousePosition.Y + m_startToDrawY );
                if ( m_clicked.track >= 0 ) {
                    int track = m_clicked.track;
                    int group = m_clicked.group;
                    int entry = m_clicked.entry;
                    if ( m_clicked.type == TimeTableType.vsq ) {
                        m_edit_mode = EditMode.None;
                    } else if ( m_clicked.type == TimeTableType.telop ) {
                        m_slide_moved = false;
                        m_dragging = m_clicked;
                        if ( m_clicked.entry < 0 ) {
                            int id = AppManager.SaveData.GetNextID();
                            m_editing_telop_original = new Telop( id );
                            m_editing_telop_original.Text = "(none)";
                            m_editing_telop_original.Start = SecFromXCoord( e.X );
                            m_editing_telop_original.End = m_editing_telop_original.Start;
                            m_editing_telop_original.Lane = m_clicked.track;
                            Command run2 = Command.GCommandAddTelop( m_editing_telop_original );
                            AppManager.SaveData.Execute( run2 );
                            m_edit_mode = EditMode.Dragging;
                        } else {
                            m_editing_telop_original = (Telop)AppManager.SaveData[m_clicked.entry].Clone();
                            m_edit_mode = EditMode.Sliding;
                        }
                    } else {
                        m_editing_group = null;
                        m_editing_group = (TimeTableGroup)AppManager.SaveData[m_clicked.type, m_clicked.group].Clone();
                        m_dragging = new Item( m_clicked.type, m_clicked.group, m_clicked.track, m_clicked.entry, m_clicked.row_index );
                        m_slide_moved = false;
                        if ( m_clicked.entry < 0 ) {
                            // エントリ追加モード
                            m_edit_mode = EditMode.Dragging;
                        } else {
                            // エントリスライドモード
                            m_edit_mode = EditMode.Sliding;
                            UpdateExpandRange( SecFromXCoord( e.X ) );
                            if ( m_clicked.type != TimeTableType.vsq ) {
                                m_slide_original = (TimeTableEntry)AppManager.SaveData[m_clicked.type, group][track][entry].Clone();
                            }
                        }
                    }
                }
            }
        }

        private void pictureBox1_MouseDoubleClick( object sender, MouseEventArgs e ) {
            if ( m_edit_mode == EditMode.None ) {
                Item clicked = GetGroupItem( e.X + m_startToDrawX, e.Y + m_startToDrawY );
                if ( clicked.type == TimeTableType.top ) {
                    float time = SecFromXCoord( e.X );
                    int nof = (int)(time * AppManager.SaveData.FrameRate);
                    if ( previewer.TrackBarMinimum <= nof && nof <= previewer.TrackBarMaximum ) {
                        previewer.TrackBarValue = nof;
                        correctPosition();
                        this.Invalidate();
                    }
                } else if ( clicked.track < 0 ) {
                    if ( clicked.type == TimeTableType.telop ) {
                        AppManager.SaveData.TelopListFolded = !AppManager.SaveData.TelopListFolded;
                        SetVScrollRange();
                        Invalidate();
                    } else {
                        if ( AppManager.SaveData[clicked.type, clicked.group] != null ) {
                            AppManager.SaveData[clicked.type, clicked.group].Folded = !AppManager.SaveData[clicked.type, clicked.group].Folded;
                            SetVScrollRange();
                            this.Invalidate();
                        }
                    }
                }
            } else {
                Item clicked = GetGroupItem( e.X + m_startToDrawX, e.Y + m_startToDrawY );
                if ( clicked.entry >= 0 ) {
                    m_clicked = clicked;
                    h_editEntry( this, new EventArgs() );
                }
            }
        }

        private void pictureBox1_MouseUp( object sender, MouseEventArgs e ) {
#if DEBUG
            Common.DebugWriteLine( "pictureBox1_MouseUp" );
            Common.DebugWriteLine( "    m_slide_moved=" + m_slide_moved );
#endif
            if ( m_edit_mode == EditMode.EditingLeft || m_edit_mode == EditMode.EditingRight/* m_editEntry*/ ) {
                #region EditMode.EditingLeft EditMode.EditRight
                int x = e.X;

                float time = SecFromXCoord( x );
                float new_begin;
                float new_end;

                TimeTableType type = m_edit_handle_ed_item.type;
                int group = m_edit_handle_ed_item.group;
                int track = m_edit_handle_ed_item.track;
                int entry = m_edit_handle_ed_item.entry;
#if DEBUG
                Common.DebugWriteLine( "pictureBox1_MouseUp; m_edit_mode==EditingLeft||EditingRight;" );
                Common.DebugWriteLine( "type=" + type + "; group=" + group + "; track=" + track + "; entry=" + entry );
#endif
                if ( track < 0 || entry < 0 ) {
                    AppManager.SaveData[type, group] = null;
                    AppManager.SaveData[type, group] = (TimeTableGroup)m_editing_group.Clone();
                    return;
                }

                if ( type == TimeTableType.telop ) {
                    new_begin = AppManager.SaveData[entry].Start;
                    new_end = AppManager.SaveData[entry].End;
                } else if ( type != TimeTableType.vsq ) {
                    new_begin = m_editing_group[track][entry].begin;
                    new_end = m_editing_group[track][entry].end;
                } else {
                    m_edit_mode = EditMode.None;
                    return;
                }

                TimeTableEntry item;
                if ( new_end <= new_begin ) {
                    // 終了時刻として開始時刻と同じか小さい時刻を指定された場合。エントリを削除
                    if ( type == TimeTableType.telop ) {
                        Command run = Command.GCommandDeleteTelop( AppManager.SaveData[entry] );
                        AppManager.Register( AppManager.SaveData.Execute( run ) );
                    } else if ( type != TimeTableType.vsq ) {
                        int g = group;
                        if ( type != TimeTableType.character ) {
                            g = -1;
                        }
                        Command run = Command.GCommandDeleteTimeTableEntry( type, g, track, AppManager.SaveData[type, group][track][entry] );
                        AppManager.Register( AppManager.SaveData.Execute( run ) );
                    }
                    AppManager.Edited = true;
                    this.Invalidate();
                    m_edit_mode = EditMode.None;
                    return;
                }
                if ( type == TimeTableType.telop ) {
                    Telop edited = (Telop)AppManager.SaveData[entry].Clone();
                    AppManager.SaveData[entry] = m_editing_telop_original;
                    Command run = Command.GCommandEditTelop( entry, edited );
                    AppManager.Register( AppManager.SaveData.Execute( run ) );
                } else if ( type != TimeTableType.vsq ) {
                    item = (TimeTableEntry)m_editing_group[track][entry].Clone();
                    item.begin = new_begin;
                    item.end = new_end;
                    if ( type != TimeTableType.character ) {
                        group = -1;
                    }
                    Command run = Command.GCommandEditGroup( type, group, AppManager.SaveData[type, group] );
                    AppManager.SaveData[type, group] = (TimeTableGroup)m_editing_group.Clone();
                    AppManager.Register( AppManager.SaveData.Execute( run ) );
#if DEBUG
                    Common.DebugWriteLine( "Command run & registered" );
#endif
                } else {
                    m_edit_mode = EditMode.None;
                    return;
                }
                pictureBox1.Cursor = Cursors.Arrow;
                AppManager.Edited = true;
                m_rcHilight = GetHilightRect( e.X, e.Y );
                this.Invalidate();
                m_edit_mode = EditMode.None;
                #endregion
            } else if ( m_edit_mode == EditMode.Dragging ) {
                #region EditMode.Dragging
                m_edit_mode = EditMode.None;
                TimeTableType type = m_dragging.type;
                int group = m_dragging.group;
                int track = m_dragging.track;
                if ( type == TimeTableType.telop ) {
                    Telop added = null;
                    for ( int i = 0; i < AppManager.SaveData.m_telop_ex2.Count; i++ ) {
                        if ( AppManager.SaveData.m_telop_ex2[i].ID == m_editing_telop_original.ID ) {
                            added = (Telop)AppManager.SaveData.m_telop_ex2[i].Clone();
                            AppManager.SaveData.m_telop_ex2.RemoveAt( i );
                            break;
                        }
                    }
                    if ( added != null && m_slide_moved ) {
                        Telop.DecideLane( AppManager.SaveData.m_telop_ex2 );
                        Command run2 = Command.GCommandAddTelop( added );
                        Command inv = AppManager.SaveData.Execute( run2 );
                        property.Editing = new ZorderItem( inv.telop.Text, ZorderItemType.telop, inv.telop.ID );
                        AppManager.Register( inv );
                        UpdateEditHandle();
                        SetVScrollRange();
                        AppManager.Edited = true;
                    }
                } else if ( type != TimeTableType.vsq ) {
                    int g = group;
                    if ( type != TimeTableType.character ) {
                        g = -1;
                    }
                    Command run = Command.GCommandEditGroup( type, g, AppManager.SaveData[type, group] );
                    AppManager.SaveData[type, group] = null;
                    AppManager.SaveData[type, group] = (TimeTableGroup)m_editing_group.Clone();
                    if ( m_slide_moved ) {
                        AppManager.Register( AppManager.SaveData.Execute( run ) );
                        AppManager.Edited = true;
                    }
                }
                m_slide_moved = false;
                //timerTimeLine.Enabled = true;
                this.Invalidate();
                #endregion
            } else if ( m_edit_mode == EditMode.Sliding ) {
                #region EditMode.Sliding
                TimeTableType type = m_dragging.type;
                int group = m_dragging.group;
                int track = m_dragging.track;
                int entry = m_dragging.entry;
                m_edit_mode = EditMode.None;
                m_slide_moved = false;
                if ( type == TimeTableType.telop ) {
                    Telop edited = (Telop)AppManager.SaveData[m_editing_telop_original.ID].Clone();
                    AppManager.SaveData[m_editing_telop_original.ID] = (Telop)m_editing_telop_original.Clone();
                    Command run2 = Command.GCommandEditTelop( edited.ID, edited );
                    AppManager.Register( AppManager.SaveData.Execute( run2 ) );
                    AppManager.Edited = true;
                } else if ( type != TimeTableType.vsq ) {
                    int g = group;
                    if ( type != TimeTableType.character ) {
                        g = -1;
                    }
                    Command run = Command.GCommandEditTimeTableEntry( type, g, track, entry, AppManager.SaveData[type, group][track][entry] );
                    AppManager.SaveData[type, group][track][entry] = null;
                    AppManager.SaveData[type, group][track][entry] = (TimeTableEntry)m_slide_original.Clone();
                    AppManager.Register( AppManager.SaveData.Execute( run ) );
                    AppManager.Edited = true;
                }
                //timerTimeLine.Enabled = true;
                this.Invalidate();
                #endregion
            }
        }

        private void pictureBox1_Paint( object sender, PaintEventArgs e ) {
            if ( m_skip_paint ) {
                return;
            }
            Graphics g = e.Graphics;
            g.Clear( SystemColors.Control );

            int[] lanes = AppManager.GetTimeLineLanes();
            int height;
            bool always_show_vsq = AppManager.Config.FixVsqTrackPosition;
            Rectangle clip_for_vsq = new Rectangle();
            if ( always_show_vsq ) {
                m_vsq_height = (AppManager.SaveData.m_group_vsq.VisibleTracks + 2) * AppManager.Config.TrackHeight;
                clip_for_vsq = new Rectangle( 0,
                                              AppManager.Config.TrackHeight,
                                              pictureBox1.Width,
                                              (AppManager.SaveData.m_group_vsq.VisibleTracks + 1) * AppManager.Config.TrackHeight );
            }

            int total_height = 0;
            for ( int lane = 0; lane < lanes.Length; lane++ ) {
                total_height += AppManager.Config.TrackHeight;
                for ( int i = 2; i <= lanes[lane]; i++ ) {
                    int y = (i - 1) * AppManager.Config.TrackHeight - m_startToDrawY;
                    if ( always_show_vsq && lane == 0 ) {
                        y += m_startToDrawY;
                    }
                    Rectangle outline = new Rectangle( 0, total_height + y, pictureBox1.Width, AppManager.Config.TrackHeight );
                    if ( i % 2 == 0 ) {
                        g.FillRectangle( _BRS_TRACKBG_ODD, outline );
                    } else {
                        g.FillRectangle( _BRS_TRACKBG_EVEN, outline );
                    }
                }
                if ( always_show_vsq && lane == 0 ) {
                    g.ExcludeClip( clip_for_vsq );
                }
                if ( lanes[lane] >= 2 ) {
                    total_height += (lanes[lane] - 1) * AppManager.Config.TrackHeight;
                }
            }

            // 小節毎の線
            g.ResetClip();
            if ( menuVisualBars.Checked ) {
                IEnumerable<BarLineType> blte = AppManager.SaveData.GetBarLineTypeEnumerator( AppManager.Config.QuantizeMode, AppManager.Config.QuantizeTripletEnabled );
                foreach ( BarLineType barsec in blte ) {
                    int x = (int)(barsec.Time * AppManager.Config.PixelPerSec) - m_startToDrawX;
                    if ( x > pictureBox1.Width ) {
                        break;
                    } else if ( 0 < x ) {
                        if ( barsec.IsSeparator ) {
                            g.DrawLine( new Pen( Color.FromArgb( 161, 157, 136 ) ),
                                        new Point( x, 0 ),
                                        new Point( x, pictureBox1.Height ) );
                        } else {
                            g.DrawLine( new Pen( Color.FromArgb( 209, 204, 172 ) ),
                                        new Point( x, 0 ),
                                        new Point( x, pictureBox1.Height ) );
                        }
                    }
                }
            }

            g.ExcludeClip( clip_for_vsq );
            total_height = AppManager.Config.TrackHeight;
            if ( !always_show_vsq ) {
                DrawTimeTableGroup( g,
                                    new Point( 0, total_height - m_startToDrawY ),
                                    out height,
                                    AppManager.SaveData.m_group_vsq,
                                    _( "VSQ Tracks" ) );
                total_height += height;
            } else {
                total_height = m_vsq_height;
            }

            for ( int i = 0; i < AppManager.SaveData.m_groups_character.Count; i++ ) {
                DrawTimeTableGroup( g,
                                    new Point( 0, total_height - m_startToDrawY ),
                                    out height,
                                    AppManager.SaveData.m_groups_character[i],
                                    _( "Character" ) + "(" + AppManager.SaveData.m_groups_character[i].Character.Name + ")" );
                total_height += height;
            }

            DrawTelop( g,
                       new Point( 0, total_height - m_startToDrawY ),
                       out height,
                       _( "Telop" ) );
            total_height += height;

            DrawTimeTableGroup( g,
                                 new Point( 0, total_height - m_startToDrawY ),
                                 out height,
                                 AppManager.SaveData.m_group_another,
                                 _( "Another Images" ) );
            total_height += height;

            DrawTimeTableGroup( g,
                                 new Point( 0, total_height - m_startToDrawY ),
                                 out height,
                                 AppManager.SaveData.m_group_plugin,
                                 _( "Plugin" ) );

            if ( always_show_vsq ) {
                g.ResetClip();
                DrawTimeTableGroup( g,
                                     new Point( 0, AppManager.Config.TrackHeight ),
                                     out height,
                                     AppManager.SaveData.m_group_vsq,
                                     _( "VSQ Tracks" ) );
                total_height += height;
            }

            // 画面に一定時間ごとのラインを引く
            g.FillRectangle( new SolidBrush( TOOL_COLOR ), 0, 0, pictureBox1.Width, AppManager.Config.TrackHeight );
            // リピートエリアを別色で描く
            g.FillRectangle( new SolidBrush( REPEAT_AREA ),
                             new Rectangle( (int)(RepeatStart * AppManager.Config.PixelPerSec - m_startToDrawX),
                                            0,
                                            (int)((RepeatEnd - RepeatStart) * AppManager.Config.PixelPerSec),
                                            AppManager.Config.TrackHeight ) );
            int start_to_draw_x = m_startToDrawX;
            int start_sec = (int)((double)(start_to_draw_x) / AppManager.Config.PixelPerSec) / AppManager.Config.TimeLineInterval;
            if ( start_sec == 0 ) {
                start_sec = 1;
            }
            int end_sec = (int)((double)(start_to_draw_x + pictureBox1.Width) / AppManager.Config.PixelPerSec) / AppManager.Config.TimeLineInterval + 1;
            for ( int i = start_sec; i <= end_sec; i++ ) {
                int x = (int)(i * AppManager.Config.TimeLineInterval * AppManager.Config.PixelPerSec) - start_to_draw_x;
                g.DrawString( i * AppManager.Config.TimeLineInterval + " sec",
                              AppManager.Config.Font.GetFont(),
                              Brushes.Black,
                              new Point( x, AppManager.Config.VerticalStringOffset ) );
                g.DrawLine( new Pen( Color.FromArgb( 128, Color.Black ) ),
                            new Point( x, 0 ), new Point( x, pictureBox1.Height ) );
            }

            if ( m_edit_mode == EditMode.Selected/* m_editMode*/ ) {
                g.DrawRectangle( HILIGHT_EDIT, m_rcHilight );
            } else {
                g.DrawRectangle( HILIGHT, m_rcHilight );
            }

            // カーソル位置に縦線
            int cursor;
            float now = Now;
            if ( menuVisualSync.Checked && AppManager.Config.SyncAtCentre ) {
                float w = pictureBox1.Width / 2 / AppManager.Config.PixelPerSec;
                if ( now < w || AppManager.SaveData.m_totalSec - w < now ) {
                    cursor = (int)(now * AppManager.Config.PixelPerSec - m_startToDrawX);
                } else {
                    cursor = pictureBox1.Width / 2;
                }
            } else {
                cursor = (int)(now * AppManager.Config.PixelPerSec - m_startToDrawX);
            }
            g.DrawLine( new Pen( Color.Black, 2.0f ), new Point( cursor, 0 ), new Point( cursor, pictureBox1.Height ) );
            g.DrawLine(
                    Pens.Black,
                    new Point( m_mousePosition.X, 0 ),
                    new Point( m_mousePosition.X, pictureBox1.Height ) );

            if ( always_show_vsq ) {
                g.DrawLine( new Pen( Color.Black, 2 ),
                            new Point( 0, m_vsq_height ),
                            new Point( pictureBox1.Width, m_vsq_height ) );
            }
        }
        #endregion

        private void preview_image_MouseLeave( object sender, EventArgs e ) {
            TimeSpan ts = DateTime.Now.Subtract( m_preview_time );
            if ( ts.TotalMilliseconds > 200 ) {
                preview_image.Visible = false;
            }
        }

        #region menuHelp
        private void menuHelpDebugExtract_Click( object sender, EventArgs e ) {
#if DEBUG
            /*            using ( OpenFileDialog dlg = new OpenFileDialog() ) {
                if ( dlg.ShowDialog() == DialogResult.OK ) {
                    string file = dlg.FileName;
                    string dir = Path.GetDirectoryName( file );
                    string fname = Path.GetFileNameWithoutExtension( file );
                    float scale = 0.45f;
                    using ( Character3 chara = new Character3( file ) ) {
                        foreach ( ImageEntry img in chara ) {
                            float width = img.image.Width;// * scale;
                            float height = img.image.Height;//                            *scale;
                            //using ( Bitmap t = new Bitmap( (int)width, (int)height, PixelFormat.Format32bppArgb ) )
                            //using ( Graphics g = Graphics.FromImage( t ) ) {
                            //g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                            //g.DrawImage( img.image, 0f, 0f, width, height );
                            img.image.Save( Path.Combine( dir, fname + "_" + img.title + ".png" ) );
                            //}
                        }
                    }
                }
            }
*/
#endif
        }

        private void menuHelpBugReport_Click( object sender, EventArgs e ) {
            BugReport dlg = new BugReport();
            dlg.Show();
        }

        private void menuHelpDebugEditCharacter_Click( object sender, EventArgs e ) {
#if DEBUG

#endif
        }

        private void menuHelpDebugInverseImages_Click( object sender, EventArgs e ) {
#if DEBUG

#endif
        }

        private static string GetAssemblyNameAndVersion( Type t ) {
            Assembly a = Assembly.GetAssembly( t );
            AssemblyFileVersionAttribute afva = (AssemblyFileVersionAttribute)Attribute.GetCustomAttribute( a, typeof( AssemblyFileVersionAttribute ) );
            return a.GetName().Name + " v" + afva.Version;
        }

        /// <summary>
        /// バージョン情報を表示
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void menuHelpVersionInfo_Click( object sender, EventArgs e ) {
            if ( m_version_form == null ) {
                string version_str = AppManager.VERSION + "\n\n" +
                                     GetAssemblyNameAndVersion( typeof( Boare.Lib.AppUtil.Misc ) ) + "\n" +
                                     GetAssemblyNameAndVersion( typeof( Boare.Lib.Media.AviWriterVcm ) ) + "\n" +
                                     GetAssemblyNameAndVersion( typeof( Boare.Lib.Vsq.VsqFile ) ) + "\n" +
#if DEBUG
                GetAssemblyNameAndVersion( typeof( Boare.Lib.Swf.SwfWriter ) ) + "\n" +
#endif
                GetAssemblyNameAndVersion( typeof( bocoree.math ) );
                m_version_form = new Boare.Lib.AppUtil.VersionInfo( _( "LipSync" ), version_str );
                m_version_form.Font = AppManager.Config.Font.GetFont();
                m_version_form.AuthorList = m_credit;
                m_version_form.AppNameColor = Color.RoyalBlue;
                m_version_form.VersionColor = Color.DimGray;
#if !DEBUG
                m_version_form.Credit = AppManager.author_list;
#endif
                m_version_form.FormClosed += new FormClosedEventHandler( m_version_form_FormClosed );
                m_version_form.Show();
            }
        }
        #endregion

        void m_version_form_FormClosed( object sender, FormClosedEventArgs e ) {
            m_version_form.Dispose();
            m_version_form = null;
        }

        #region Form1
        private void Form1_Shown( object sender, EventArgs e ) {
            m_initialized = true;
            ResizePanel2();
        }

        private void Form1_Load( object sender, EventArgs e ) {
#if MONO
            Common.DebugWriteLine( "this assembly was compiled under the define of \"NET_2_0\"" );
#endif
            ResizePanel2();
            ApplyFont( AppManager.Config.Font.GetFont() );

            // プラグインを読み込み
            //インストールされているプラグインを調べる
            //すべてのプラグインクラスのインスタンスを作成する
            AppManager.SaveData.m_plugins = PluginInfo.FindPlugins();

            AppManager.SaveData.m_group_plugin = new TimeTableGroup( _( "Plugin" ), -1, null );

            AppManager.SaveData.m_plugins_config = new List<PluginConfig>();
            for ( int i = 0; i < AppManager.SaveData.m_plugins.Length; i++ ) {
                AppManager.SaveData.m_plugins_config.Add( new PluginConfig( AppManager.SaveData.m_plugins[i].Instance.Name, AppManager.SaveData.m_plugins[i].Instance.Config, Path.GetFileName( AppManager.SaveData.m_plugins[i].Location ) ) );
                AppManager.SaveData.m_group_plugin.Add( new TimeTable( AppManager.SaveData.m_plugins_config[i].ID, 0, TimeTableType.plugin, null ) );
            }

            /*
             * プラグインの種類に応じて、メインメニューを更新
             */
            // プラグイン設定
            if ( AppManager.SaveData.m_plugins.Length > 0 ) {
                for ( int i = 0; i < AppManager.SaveData.m_plugins.Length; i++ ) {
                    if ( (AppManager.SaveData.m_plugins[i].Instance.Type & Plugin.Constants.LS_NO_EVENT_HANDLER) != Plugin.Constants.LS_NO_EVENT_HANDLER ) {
                        menuToolPluginConfig.DropDownItems.Add( AppManager.SaveData.m_plugins_config[i].ID, null, new EventHandler( h_pluginSetting ) );
                    }
                }
            }

            // プラグインの情報
            menuHelpPluginInfo.DropDownItems.Clear();
            for ( int i = 0; i < AppManager.SaveData.m_plugins.Length; i++ ) {
                menuHelpPluginInfo.DropDownItems.Add( AppManager.SaveData.m_plugins[i].Instance.Name, null, new EventHandler( h_pluginInfo ) );
            }

            AppManager.SaveData.m_group_vsq = new TimeTableGroup( _( "VSQ Tracks" ), -1, null );
            AppManager.SaveData.m_groups_character = new List<TimeTableGroup>();
            AppManager.SaveData.m_group_another = new TimeTableGroup( _( "Another images" ), -1, null );
            SettingsEx.CommandExecuted += new CommandExecutedEventHandler( SettingsEx_CommandExecuted );

            AppManager.SaveData.m_screenWidth = this.Width;
            AppManager.SaveData.m_screenHeight = this.Height;

            AppManager.Edited = false;

            if ( m_filePath != "" ) {
                Read( m_filePath );
            }
            SetHScrollRange();
            SetVScrollRange();

            AppManager.SaveData.UpdateZorder();

            preview_image.Parent = pictureBox1;

            QuantizeMenuCheckedStateUpdate();
            UpdateGridList();

            property.PropertyValueChanged += new PropertyValueChangedEventHandler( property_PropertyValueChanged );
            property.TelopAdding += new TelopAddingEventHandler( property_TelopAdding );
            property.EditingItemChanged += new EditingItemChangedEventHandler( property_EditingItemChanged );
            property.TelopDeleting += new TelopDeletingEventHandler( property_TelopDeleting );
            property.ListUpdateRequired += new ListUpdateRequiredEventHandler( UpdateObjectList );
            property.UpdateLayout();

            previewer.Image = new Bitmap( AppManager.SaveData.m_movieSize.Width, AppManager.SaveData.m_movieSize.Height );
            using ( Graphics g = Graphics.FromImage( previewer.Image ) ) {
                AppManager.SaveData.DrawTo( g, new Size( AppManager.SaveData.m_movieSize.Width, AppManager.SaveData.m_movieSize.Height ), 0.0f, false );
            }

#if DEBUG
            FormCommandHistory fch = new FormCommandHistory();
            fch.Show();
#endif
        }

        private void Form1_FormClosing( object sender, FormClosingEventArgs e ) {
            if ( AppManager.Edited ) {
                //MessageBox.Show( "Form1_FormClosing" );
                DialogResult result = requestIntention();
                switch ( result ) {
                    case DialogResult.Yes:
                        if ( m_filePath == "" ) {
                            if ( saveFileDialog1.ShowDialog() == DialogResult.OK ) {
                                m_filePath = saveFileDialog1.FileName;
                                Save( m_filePath );
                            } else {
                                return;
                            }
                        } else {
                            Save( m_filePath );
                        }
                        break;
                    case DialogResult.Cancel:
                        e.Cancel = true;
                        return;
                }
            }
            if ( m_player != null ) {
                m_player.Stop();
                m_player.Close();
            }
            if ( m_preview_thread != null ) {
                m_preview_thread.Abort();
                while ( m_preview_thread.IsAlive ) {
                    Application.DoEvents();
                }
            }
            SaveConfig();
        }

        private void Form1_DragEnter( object sender, DragEventArgs e ) {
            e.Effect = DragDropEffects.All;
        }

        private void Form1_DragDrop( object sender, DragEventArgs e ) {
            if ( e.Data.GetDataPresent( DataFormats.FileDrop ) ) {
                string[] filename = (string[])e.Data.GetData( DataFormats.FileDrop );
                if ( Path.GetExtension( filename[0] ).ToLower() == ".vsq" || Path.GetExtension( filename[0] ).ToLower() == ".ust" ) {
                    // vsqファイル
                    ReadVsq( filename[0] );
                } else if ( Path.GetExtension( filename[0] ).ToLower() == ".lse" ) {
                    // LipSync Editorファイル
                    Read( filename[0] );
                    m_filePath = filename[0];
                    UpdateFormTitle();
                    SetHScrollRange();
                    SetVScrollRange();
                    //rebuildDrawing();
                    this.Invalidate();
                }
            }
        }

        private void Form1_Paint( object sender, PaintEventArgs e ) {
            if ( m_skip_paint ) {
                return;
            }
            float now;
            if ( !AviWriting && !AppManager.Config.PreviewHidden ) {
#if OBSOLETE_MODE
                if ( PreviewP.Image != null ) {
                    PreviewP.Image.Dispose();
                }
                PreviewP.Image = getPicture( now );
#endif
                //PreviewP.Refresh();
                //previewer.Preview.Invalidate();
            }

            float speed = m_player.Speed;
            previewer.LabelSpeedText = "x" + speed.ToString( "0.00" );

            pictureBox1.Refresh();
            side.Refresh();
        }

        private void Form1_LocationOrSizeChanged( object sender, EventArgs e ) {
            if ( AppManager.Config != null ) {
                if ( this.WindowState == FormWindowState.Normal ) {
                    AppManager.Config.WindowPosition = this.Bounds;
                }
                AppManager.Config.WindowIsMaximized = (this.WindowState == FormWindowState.Maximized);
            }
        }

        private void Form1_Activated( object sender, EventArgs e ) {
            m_edit_mode = EditMode.None;
        }

        private void Form1_Deactivate( object sender, EventArgs e ) {
            m_edit_mode = EditMode.None;
        }
        #endregion

        #region bgWorkAvi
        private void bgWorkAvi_DoWork( object sender, DoWorkEventArgs e ) {
            IAviWriter writer = null;
            AviOutputArguments args = (AviOutputArguments)e.Argument;
            bool is_raw_mode = args.IsRawMode;
            if ( File.Exists( args.AviFile ) ) {
                File.Delete( args.AviFile );
            }
            Size size = AppManager.SaveData.m_movieSize;
            m_avi_cancel = false;

            long start_frame;
            if ( args.StartSpecified ) {
                start_frame = (long)(args.Start * AppManager.SaveData.FrameRate);
            } else {
                start_frame = 0L;
            }

            long end_frame;
            if ( args.EndSpecified ) {
                end_frame = (long)(args.End * AppManager.SaveData.FrameRate);
            } else {
                end_frame = (long)((AppManager.SaveData.m_totalSec) * AppManager.SaveData.FrameRate);
            }
            long total_frames = end_frame - start_frame + 1;
#if !DEBUG
            try {
#endif
            Bitmap bmp = null;
            if ( args.UseVfwEncoder ) {
                bmp = new Bitmap( size.Width, size.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb );
                if ( is_raw_mode ) {
                    RawAvi2Writer awraw = new RawAvi2Writer();
                    bool ret = awraw.Open( args.AviFile,
                                           AppManager.SaveData.DwScale,
                                           AppManager.SaveData.DwRate,
                                           size.Width,
                                           size.Height,
                                           Process.GetCurrentProcess().MainWindowHandle );
                    if ( !ret ) {
                        return;
                    }
                    writer = awraw;
                } else {
                    AviWriterVfw awvfw = new AviWriterVfw();
                    bool ret = awvfw.Open( args.AviFile,
                                           AppManager.SaveData.DwScale,
                                           AppManager.SaveData.DwRate,
                                           size.Width,
                                           size.Height,
                                           Process.GetCurrentProcess().MainWindowHandle );
                    if ( !ret ) {
                        return;
                    }
                    writer = awvfw;
                }
            } else {
                bmp = args.IsTransparent ?
                    new Bitmap( size.Width, size.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb ) :
                    new Bitmap( size.Width, size.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb );
                AviWriterVcm awvcm = new AviWriterVcm();
                bool ret = awvcm.Open( args.AviFile, 
                                       AppManager.SaveData.DwScale,
                                       AppManager.SaveData.DwRate, 
                                       size.Width, 
                                       size.Height, 
                                       !is_raw_mode, 
                                       args.IsTransparent, 
                                       Process.GetCurrentProcess().MainWindowHandle );
                if ( !ret ) {
                    return;
                }
                writer = awvcm;
            }
            using ( Graphics g = Graphics.FromImage( bmp ) ) {
                for ( long frame = start_frame; frame <= end_frame; frame++ ) {
                    float now = (float)frame / AppManager.SaveData.FrameRate;
                    using ( Bitmap frm = GetPicture( now, args.IsTransparent ) ) {
                        frm.RotateFlip( RotateFlipType.Rotate180FlipX );
                        g.DrawImage( frm, 0, 0, size.Width, size.Height );
                    }
                    try {
                        writer.AddFrame( bmp );
                    } catch ( Exception ex ) {
#if DEBUG
                        Common.LogPush( ex );
#endif
                        writer.Close();
                        this.Invoke( new Form1_AviWritingChange( ChangeAviWriting ), new object[] { false } );
                        return;
                    }
                    bgWorkAvi.ReportProgress( (int)((double)(frame - start_frame) / (double)(total_frames) * 100.0), new long[] { frame - start_frame, total_frames } );
                    if ( m_avi_cancel ) {
                        bmp.Dispose();
                        g.Dispose();
                        writer.Close();
                        m_avi_cancel = false;
                        return;
                    }
                }
                writer.Close();

                string audio_file = AppManager.SaveData.m_audioFile;

#if DEBUG
                Common.DebugWriteLine( "bgWorkAvi_DoWork" );
                Common.DebugWriteLine( "    args.IsWaveMergeRequired=" + args.IsWaveMergeRequired );
#endif
                if ( args.IsWaveMergeRequired ) {
                    #region merge wave file
                    if ( File.Exists( audio_file ) && AppManager.Config.PathFFmpeg != "" && File.Exists( AppManager.Config.PathFFmpeg ) ) {
                        string tmp_avi = Misc.GetTempFileNameIn( Path.GetDirectoryName( args.AviFile ), ".avi" );
                        File.Move( args.AviFile, tmp_avi );
                        // ffmpeg -i movie.mpeg -i audio.wav combined.avi
                        long frames = end_frame - start_frame + 1;
                        m_ffmpeg = new Process();
                        m_ffmpeg.StartInfo.FileName = "\"" + AppManager.Config.PathFFmpeg + "\"";
                        m_ffmpeg.StartInfo.Arguments = "-i \"" + audio_file + "\" -i \"" + tmp_avi + "\" -vframes " + frames + " -vcodec copy -acodec copy \"" + args.AviFile + "\"";
#if DEBUG
                        Common.DebugWriteLine( "    m_ffmpeg.StarInfo.Arguments=" + m_ffmpeg.StartInfo.Arguments );
#endif
                        m_ffmpeg.StartInfo.CreateNoWindow = true;
                        m_ffmpeg.StartInfo.UseShellExecute = false;
                        m_ffmpeg.StartInfo.RedirectStandardError = true;
                        m_ffmpeg.Start();

                        this.m_stdout = new Thread( new ParameterizedThreadStart( this.FFMpegOutputRead ) );
                        this.m_stdout.Name = "output_ffmpeg";
                        this.m_stdout.Start( end_frame - start_frame );
                        m_ffmpeg.WaitForExit();
                        if ( args.IsDeleteIntermediateRequired ) {
                            File.Delete( tmp_avi );
                        }
                    }
                    #endregion
                }

                if ( args.IsFlvEncodeRequired && AppManager.Config.PathMEncoder != "" && File.Exists( AppManager.Config.PathMEncoder ) ) {
                    #region encode flv
                    //string flv_file = @"C:\test.flv";
                    string flv_file = Path.Combine( Path.GetDirectoryName( args.AviFile ), Path.GetFileNameWithoutExtension( args.AviFile ) + ".flv" );
                    string arguments = "\"" + args.AviFile + "\" -of lavf -lavfopts format=flv -ovc lavc -lavcopts vcodec=flv:vbitrate=500:mbd=2:ss:aiv:umv:preme=2:mv0:qprd:trell:v4mv:cbp -oac mp3lame -lameopts abr:br=128 -vf scale=" + size.Width + ":" + size.Height + " -sws 9 -af resample=44100 -o \"" + flv_file + "\"";
                    m_mencoder = new Process();
                    m_mencoder.StartInfo.FileName = "\"" + AppManager.Config.PathMEncoder + "\"";
                    m_mencoder.StartInfo.Arguments = arguments;
                    m_mencoder.StartInfo.CreateNoWindow = true;
                    m_mencoder.StartInfo.UseShellExecute = false;
                    m_mencoder.StartInfo.RedirectStandardOutput = true;
                    m_mencoder.Start();

                    m_stdout = new Thread( new ParameterizedThreadStart( this.MEncoderOutputRead ) );
                    m_stdout.Name = "stdout_mencoder";
                    m_stdout.Start( end_frame - start_frame );

                    m_mencoder.WaitForExit();

                    if ( args.IsDeleteIntermediateRequired ) {
                        File.Delete( args.AviFile );
                    }

                    #endregion
                } else if ( args.IsMp4EncodeRequired && AppManager.Config.PathFFmpeg != "" && File.Exists( AppManager.Config.PathFFmpeg ) ) {
                    #region encode mp4
                    try {
                        // ffmpeg -i teaser8000k1280_720_3.avi -r 24 -s 512x288 -refs 1 -bf 2 -flags2 dct8x8 -partitions parti8x8+partp8x8+partb8x8 -sc_threshold 50 -qpel -trell -me hex -directpred 3 -bufsize 128 -b 472k -bt 472k -mbd 2 -preme 2         -f mp4 -vcodec libx264                 -an -pass 1 -passlogfile "passlog" enc.mp4
                        // ffmpeg -i teaser8000k1280_720_3.avi -r 24 -s 512x288 -refs 1 -bf 2 -flags2 dct8x8 -partitions parti8x8+partp8x8+partb8x8 -sc_threshold 50 -qpel -trell -me hex -directpred 3 -bufsize 128 -b 472k -bt 472k -mbd 2 -preme 2 -ab 64k -f mp4 -vcodec libx264 -acodec libfaac     -pass 2 -passlogfile "passlog" enc.mp4
                        string mp4_file = Path.Combine( Path.GetDirectoryName( args.AviFile ), Path.GetFileNameWithoutExtension( args.AviFile ) + ".mp4" );
                        string arguments = "";
                        string work_dir = Path.Combine( Application.StartupPath, "temp" );
                        if ( !Directory.Exists( work_dir ) ) {
                            Directory.CreateDirectory( work_dir );
                        }

                        // first pass
                        arguments = "-i \"" + args.AviFile + "\" -refs 1 -bf 2 -flags2 dct8x8 -partitions parti8x8+partp8x8+partb8x8 -sc_threshold 40 -qpel -trell -me hex -directpred 3 -bufsize 128 -b 472k -bt 472k -mbd 2 -preme 2 -f mp4 -vcodec libx264 -an -pass 1 -passlogfile \"passlog\" -y \"" + mp4_file + "\"";
#if DEBUG
                        Common.DebugWriteLine( "1st pass arguments=" + arguments );
#endif
                        m_ffmpeg = new Process();
                        m_ffmpeg.StartInfo.WorkingDirectory = work_dir;
                        m_ffmpeg.StartInfo.FileName = "\"" + AppManager.Config.PathFFmpeg + "\"";
                        m_ffmpeg.StartInfo.Arguments = arguments;
                        m_ffmpeg.StartInfo.CreateNoWindow = true;
                        m_ffmpeg.StartInfo.UseShellExecute = false;
                        m_ffmpeg.StartInfo.RedirectStandardError = true;
                        m_ffmpeg.Start();
                        this.m_stdout = new Thread( new ParameterizedThreadStart( this.FFMpegOutputRead ) );
                        this.m_stdout.Name = "output_ffmpeg";
                        this.m_stdout.Start( end_frame - start_frame );
                        m_ffmpeg.WaitForExit();

                        // 2nd pass
                        arguments = "-i \"" + args.AviFile + "\" -refs 1 -bf 2 -flags2 dct8x8 -partitions parti8x8+partp8x8+partb8x8 -sc_threshold 40 -qpel -trell -me hex -directpred 3 -bufsize 128 -b 472k -bt 472k -mbd 2 -preme 2 -ab 64k -f mp4 -vcodec libx264 -acodec libfaac -pass 2 -passlogfile \"passlog\" -y \"" + mp4_file + "\"";
#if DEBUG
                        Common.DebugWriteLine( "2nd pass arguments=" + arguments );
#endif
                        m_ffmpeg = new Process();
                        m_ffmpeg.StartInfo.WorkingDirectory = work_dir;
                        m_ffmpeg.StartInfo.FileName = "\"" + AppManager.Config.PathFFmpeg + "\"";
                        m_ffmpeg.StartInfo.Arguments = arguments;
                        m_ffmpeg.StartInfo.CreateNoWindow = true;
                        m_ffmpeg.StartInfo.UseShellExecute = false;
                        m_ffmpeg.StartInfo.RedirectStandardError = true;
                        m_ffmpeg.Start();
                        this.m_stdout = new Thread( new ParameterizedThreadStart( this.FFMpegOutputRead ) );
                        this.m_stdout.Name = "output_ffmpeg";
                        this.m_stdout.Start( end_frame - start_frame );
                        m_ffmpeg.WaitForExit();
                    } catch ( Exception ex ) {
#if DEBUG
                        Common.DebugWriteLine( ex.ToString() );
#endif
                    }
                    #endregion
                }

            }


            //mencoder test.avi -of lavf -lavfopts format=flv -ovc lavc -lavcopts vcodec=flv:vbitrate=500:mbd=2:ss:aiv:umv:preme=2:mv0:qprd:trell:v4mv:cbp -oac mp3lame -lameopts abr:br=128 -passlogfile pass.log -vf scale=512:384 -sws 9 -af resample=44100 -o test.flv
#if !DEBUG
            } catch {
                writer.Close();
                MessageBox.Show(
                    _( "Initialization of video compression failed.\nThis video codec may require image width in multiples of certain number." ),
                    _( "Error" ),
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Exclamation
                );
            }
#endif
        }

        private void bgWorkAvi_ProgressChanged( object sender, ProgressChangedEventArgs e ) {
            long[] stat = (long[])e.UserState;
            this.Text = _( "AVI Progress" ) + " " + e.ProgressPercentage + "%  [" + stat[0] + "/" + stat[1] + "]";
        }

        private void bgWorkAvi_RunWorkerCompleted( object sender, RunWorkerCompletedEventArgs e ) {
            this.Invoke( new Form1_AviWritingChange( ChangeAviWriting ), new object[] { false } );
            m_avi_cancel = false;
            UpdateFormTitle();
        }
        #endregion

        #region menuEdit
        /// <summary>
        /// キャンバス背景色の変更
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void menuEditBGColor_Click( object sender, EventArgs e ) {
            colorDialog1.Color = AppManager.SaveData.CANVAS_BACKGROUND;
            if ( colorDialog1.ShowDialog() == DialogResult.OK ) {
                Command run = Command.GCommandChangeBackgroundColor( colorDialog1.Color );
                AppManager.Register( AppManager.SaveData.Execute( run ) );
                AppManager.Edited = true;
                this.Invalidate();
            }
        }

        private void menuEditAddCharacter_Click( object sender, EventArgs e ) {
            List<string> plugins = new List<string>();
            for ( int i = 0; i < AppManager.SaveData.m_plugins.Length; i++ ) {
                if ( (AppManager.SaveData.m_plugins[i].Instance.Type & Plugin.Constants.LS_TYPE_CHARACTER) == Plugin.Constants.LS_TYPE_CHARACTER ) {
                    plugins.Add( AppManager.SaveData.m_plugins_config[i].ID );
                }
            }
            using ( SelectCharacater sc = new SelectCharacater( plugins ) ) {
                if ( sc.ShowDialog() == DialogResult.OK ) {
                    using ( TimeTable tempo = new TimeTable( "", 0, TimeTableType.vsq, null ) ) {
                        GenerateLipsyncFromVsq( tempo, sc.Character, true );
                    }
                    AppManager.Edited = true;
                    AppManager.Config.LastCharacterPath = sc.Path;
                    UpdateObjectList();
                    SetVScrollRange();
                    this.Invalidate();
                }
            }
        }

        private void menuEditVideoLength_Click( object sender, EventArgs e ) {
            using ( InputBox box = new InputBox( _( "Video size configuration" ), _( "Input video length in second" ) ) ) {
                box.rText = AppManager.SaveData.m_totalSec.ToString();
                if ( box.ShowDialog() == DialogResult.OK ) {
                    float buff = AppManager.SaveData.m_totalSec;
                    try {
                        buff = float.Parse( box.rText );
                    } catch {
                        MessageBox.Show(
                            _( "Invalid value has been entered" ),
                            _( "Error" ),
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Exclamation
                        );
                        buff = AppManager.SaveData.m_totalSec;
                    } finally {
                        AppManager.SaveData.m_totalSec = buff;
                    }
                    //rebuildDrawing();
                    AppManager.Edited = true;
                    AppManager.SaveData.UpdateZorder();
                    SetHScrollRange();
                    this.Invalidate();
                }
            }
        }

        private void menuEditShiftTimeline_Click( object sender, EventArgs e ) {
            using ( InputBox ibox = new InputBox( _( "Shift all time-tables" ), _( "Input shift time in second (you can enter minus value)" ) ) ) {
                if ( ibox.ShowDialog() == DialogResult.OK ) {
                    float shift;
                    try {
                        shift = float.Parse( ibox.rText );
                    } catch {
                        MessageBox.Show(
                            _( "Invalid value has been entered" ),
                            _( "Error" ),
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Exclamation
                        );
                        return;
                    }
                    Command run = Command.GCommandShiftTimeTable( TimeTableType.whole, -1, shift );
                    AppManager.Register( AppManager.SaveData.Execute( run ) );
                    AppManager.Edited = true;
                }
            }
        }

        private void menuEditFrameRate_Click( object sender, EventArgs e ) {
            using ( FormSetFrameRate dlg = new FormSetFrameRate( AppManager.SaveData.DwRate, AppManager.SaveData.DwScale ) ) {
                if ( dlg.ShowDialog() == DialogResult.OK ) {
                    uint rate = dlg.DwRate;
                    uint scale = dlg.DwScale;
                    if ( rate <= 0 || scale <= 0 ) {
                        MessageBox.Show(
                            _( "Invalid value has been entered" ),
                            _( "Error" ),
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Exclamation
                        );
                    } else {
#if DEBUG
                        Common.DebugWriteLine( "menuEditFrameRate_Click; rate=" + rate + "; scale=" + scale );
#endif
                        Command run = Command.GCommandChangeFps( rate, scale );
                        AppManager.Register( AppManager.SaveData.Execute( run ) );
                        ChangeBitrate();
                        AppManager.Edited = true;
#if DEBUG
                        Common.DebugWriteLine( "menuEditFrameRate_Click; s.DwRate=" + AppManager.SaveData.DwRate + "; s.DwScale=" + AppManager.SaveData.DwScale );
#endif
                    }
                }
            }
        }

        private void menuEditUndo_Click( object sender, EventArgs e ) {
            CommandType next = AppManager.GetNextUndoCommandType();
            AppManager.Undo();
            if ( next == CommandType.changeFps ) {
                ChangeBitrate();
            }
            UpdateObjectList();
            AppManager.Edited = true;
            this.Invalidate();
        }

        private void menuEditRedo_Click( object sender, EventArgs e ) {
            CommandType next = AppManager.GetNextRedoCommandType();
            AppManager.Redo();
            if ( next == CommandType.changeFps ) {
                ChangeBitrate();
            }
            UpdateObjectList();
            AppManager.Edited = true;
            this.Invalidate();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void menuEditZOrder_Click( object sender, EventArgs e ) {
            ZOrder zorder = new ZOrder();
            zorder.Clear();
            int count = 0;
            int cur_z = -1;

            #region フォームを作成

            // まず、zオーダーを設定可能なオブジェクトの個数を数える
            // プラグイン
            count += AppManager.SaveData.m_plugins.Length;
            bool[] b_plugins = new bool[AppManager.SaveData.m_group_plugin.Count];
            for ( int i = 0; i < AppManager.SaveData.m_group_plugin.Count; i++ ) {
                b_plugins[i] = false;
                cur_z = Math.Max( cur_z, AppManager.SaveData.m_group_plugin[i].ZOrder );
            }
            // キャラクタ
            count += AppManager.SaveData.m_groups_character.Count;
            bool[] b_groups_character = new bool[AppManager.SaveData.m_groups_character.Count];
            for ( int i = 0; i < b_groups_character.Length; i++ ) {
                b_groups_character[i] = false;
                cur_z = Math.Max( cur_z, AppManager.SaveData.m_groups_character[i].ZOrder );
            }
            // その他のイメージ
            count += AppManager.SaveData.m_group_another.Count;
            bool[] b_group_another = new bool[AppManager.SaveData.m_group_another.Count];
            for ( int i = 0; i < b_group_another.Length; i++ ) {
                b_group_another[i] = false;
                cur_z = Math.Max( cur_z, AppManager.SaveData.m_group_another[i].ZOrder );
            }

            //MessageBox.Show( "count=" + count );

            ZorderItem[] list = new ZorderItem[count];
            int[] eval = new int[count];
            int[] order = new int[count];
            int index = -1;
            for ( int i = 0; i < AppManager.SaveData.m_plugins.Length; i++ ) {
                index++;
                list[index] = new ZorderItem( AppManager.SaveData.m_plugins_config[i].ID, ZorderItemType.plugin, i );
                eval[index] = AppManager.SaveData.m_group_plugin[i].ZOrder;
            }
            for ( int i = 0; i < AppManager.SaveData.m_groups_character.Count; i++ ) {
                index++;
                list[index] = new ZorderItem( AppManager.SaveData.m_groups_character[i].Text, ZorderItemType.character, i );
                eval[index] = AppManager.SaveData.m_groups_character[i].ZOrder;
            }
            for ( int i = 0; i < AppManager.SaveData.m_group_another.Count; i++ ) {
                index++;
                list[index] = new ZorderItem( AppManager.SaveData.m_group_another[i].Text, ZorderItemType.another, i );
                eval[index] = AppManager.SaveData.m_group_another[i].ZOrder;
            }

            // 並べ変え
            int change = 1;
            ZorderItem tmp;
            int itemp;
            while ( change > 0 ) {
                change = 0;
                for ( int i = 0; i < count - 1; i++ ) {
                    if ( eval[i] > eval[i + 1] ) {
                        tmp = list[i];
                        list[i] = list[i + 1];
                        list[i + 1] = tmp;
                        itemp = eval[i];
                        eval[i] = eval[i + 1];
                        eval[i + 1] = itemp;
                        change++;
                    }
                }
            }

            // ｚオーダーの大きいものから、listBox1に登録
            for ( int i = 0; i < count; i++ ) {
                zorder.itemAdd( list[i] );
            }
            #endregion

            //MessageBox.Show( "zorder.Count=" + zorder.Count );

            if ( zorder.ShowDialog() == DialogResult.OK ) {

                // フォームの応答から、zorderを再計算
                for ( int i = 0; i < zorder.Count; i++ ) {
                    AppManager.SaveData.SetZorder( zorder[i], i + 1 );
                }

                AppManager.Edited = true;
                AppManager.SaveData.UpdateZorder();
            }
            zorder.Dispose();
        }

        private void menuEditRealTime_Click( object sender, EventArgs e ) {
            UpdateFormTitle();
        }

        private void menuEdit_DropDownOpening( object sender, EventArgs e ) {
            menuEditUndo.Enabled = AppManager.IsUndoAvailable;
            menuEditRedo.Enabled = AppManager.IsRedoAvailable;
            if ( AppManager.SaveData.m_totalSec <= 0.0f ) {
                menuEditShiftTimeline.Enabled = false;
                menuEditAddCharacter.Enabled = false;
            } else {
                menuEditShiftTimeline.Enabled = true;
                menuEditAddCharacter.Enabled = true;
            }
            if ( AppManager.SaveData.m_groups_character.Count == 0 ) {
                menuEditRealTime.Enabled = false;
            } else {
                menuEditRealTime.Enabled = true;
            }
            menuEditAddCharacter.Enabled = !AppManager.Playing;
        }

        private void menuEditVideoSize_Click( object sender, EventArgs e ) {
            sizeChange();
        }

        private void menuFileOutputAvi_Click( object sender, EventArgs e ) {
            if ( AppManager.Playing ) {
                StopMusic();
            }
            initializeFirstEntry();
            showDialogCore( false );
        }

        private void menuFileOutputRawAvi_Click( object sender, EventArgs e ) {
            if ( AppManager.Playing ) {
                StopMusic();
            }
            initializeFirstEntry();
            showDialogCore( true );
        }
        #endregion

        #region xmenuFile
        private void xmenuFileClose_Click( object sender, EventArgs e ) {
            if ( AppManager.Edited ) {
                //MessageBox.Show( "Form1_FormClosing" );
                DialogResult result = requestIntention();
                switch ( result ) {
                    case DialogResult.Yes:
                        if ( m_filePath == "" ) {
                            if ( saveFileDialog1.ShowDialog() == DialogResult.OK ) {
                                m_filePath = saveFileDialog1.FileName;
                                Save( m_filePath );
                            } else {
                                return;
                            }
                        } else {
                            Save( m_filePath );
                        }
                        break;
                    case DialogResult.Cancel:
                        return;
                }
            }
            if ( m_player != null ) {
                m_player.Stop();
                m_player.Close();
            }

            AppManager.Edited = false;
            m_filePath = "";
            UpdateFormTitle();
            ClearExistingData();
            AppManager.ClearCommandBuffer();
            AppManager.SaveData.UpdateZorder();
            this.Invalidate();
        }

        private void xmenuFileOpenVsq_Click( object sender, EventArgs e ) {
            // 既存のトラックがないかどうか確認。
            int count = 0;
            count += AppManager.SaveData.m_group_vsq.Count;
            for ( int group = 0; group < AppManager.SaveData.m_groups_character.Count; group++ ) {
                count += AppManager.SaveData.m_groups_character[group].Count;
            }
            count += AppManager.SaveData.m_group_another.Count;
            count += AppManager.SaveData.m_telop_ex2.Count;
            if ( count > 0 ) {
                if ( MessageBox.Show(
                        _( "This operation will overwrite all exisiting time-tables, and can NOT undo. Would you like to continue?" ) + "\n\n" + _( "( In case you want to append new track, please right-click [VSQ Tracks] to select [Read from VSQ file]. )" ),
                        _( "Confirmation" ),
                        MessageBoxButtons.OKCancel,
                        MessageBoxIcon.Question ) != DialogResult.OK ) {
                    return;
                }
            }

            List<string> track_name = new List<string>();
            int tracks;

            // VSQファイルを開いて、解析
            openVsqDialog.FileName = AppManager.Config.LastVsqPath;
            try {
                openVsqDialog.Filter = _( "VOCALOID2 Sequence File(*.vsq)|*.vsq" ) + "|" +
                                       _( "UTAU Script File(*.ust)|*.ust" ) + "|" +
                                       _( "All Files(*.*)|*.*" );
            } catch {
                openVsqDialog.Filter = "VOCALOID2 Sequence File(*.vsq)|*.vsq|UTAU Script File(*.ust)|*.ust|All Files(*.*)|*.*";
            }
            if ( openVsqDialog.ShowDialog() != DialogResult.OK ) {
                return;
            }
            AppManager.Config.LastVsqPath = openVsqDialog.FileName;

            // 既存のtime tableを破棄
            ClearExistingData();
            tracks = 0;

            if ( openVsqDialog.FilterIndex == 0 || Path.GetExtension( openVsqDialog.FileName ).ToLower() == ".vsq" ) {
                // VsqFileを取得
                int most_lyrics_track = 0; // 一番歌詞の文字数が多かったトラックの番号
                VsqFile vsqFile = new VsqFile( openVsqDialog.FileName );
                AppManager.SaveData.m_totalSec = (float)vsqFile.getTotalSec();

                AppManager.SaveData.m_timesig_ex = new List<TimeSigTableEntry>( vsqFile.TimesigTable.ToArray() );
                AppManager.SaveData.m_tempo = new List<TempoTableEntry>( vsqFile.TempoTable.ToArray() );
                AppManager.SaveData.m_base_tempo = vsqFile.getBaseTempo();

                // 歌詞の含まれるトラック数を取得
                {
                    int most_lyrics = 0;
                    for ( int i = 0; i < vsqFile.Track.Count; i++ ) {
                        int track_num = vsqFile.Track[i].getLyricLength();
                        if ( most_lyrics < track_num ) {
                            most_lyrics_track = i;
                            most_lyrics = track_num;
                        }
                        if ( track_num > 0 ) {
                            track_name.Add( vsqFile.Track[i].Name );
                            tracks++;
                        }
                    }
                }
                most_lyrics_track--;

                // tableを更新
                for ( int track = 0; track < vsqFile.Track.Count; track++ ) {
                    int lyrics = vsqFile.Track[track].getLyricLength();
                    if ( lyrics <= 0 ) {
                        continue;
                    }
                    addTimeLineFromTrack( vsqFile, track, false );
                    // todo この辺うまく行ってない？
                }

                if ( AppManager.Config.GenerateCharacterAutomatically ) {
                    // 一番歌詞の文字数が多かったトラックの歌詞をもとに
                    // 口の動きを決める
                    GenerateLipsyncFromVsq( AppManager.SaveData.m_group_vsq[most_lyrics_track], Character3.Miku, false );
                }
            } else {
                UstFile ust_file = new UstFile( openVsqDialog.FileName );
                for ( int track = 0; track < ust_file.getTrackCount(); track++ ) {
                    for( Iterator itr = ust_file.getTrack( track ).getNoteEventIterator(); itr.hasNext(); ){
                        UstEvent ue = (UstEvent)itr.next();
                        if ( ue.Lyric == "u" ) {
                            ue.Lyric = "う";
                        }
                    }
                }
                AppManager.SaveData.m_totalSec = (float)ust_file.getTotalSec();

                AppManager.SaveData.m_timesig_ex = new List<TimeSigTableEntry>();
                AppManager.SaveData.m_timesig_ex.Add( new TimeSigTableEntry( 0, 4, 4, 0 ) ); //todo: bar_countは零？
                AppManager.SaveData.m_tempo = new List<TempoTableEntry>( ust_file.getTempoList().ToArray() );
                AppManager.SaveData.m_base_tempo = ust_file.getBaseTempo();

                // tableを更新
                for ( int track = 0; track < ust_file.getTrackCount(); track++ ) {
                    AddTimeLineFromUst( ust_file, track, false );
                }

                if ( AppManager.Config.GenerateCharacterAutomatically ) {
                    // 一番歌詞の文字数が多かったトラックの歌詞をもとに
                    // 口の動きを決める
                    GenerateLipsyncFromVsq( AppManager.SaveData.m_group_vsq[0], Character3.Miku, false );
                }
            }

            // そのほかのイメージトラック用のグループを追加
            AppManager.SaveData.m_group_another = null;
            AppManager.SaveData.m_group_another = new TimeTableGroup( _( "Another images" ), -1, null );

            // スクリーンの（仮想）サイズを更新
            SetHScrollRange();
            SetVScrollRange();

            AppManager.ClearCommandBuffer();
            AppManager.SaveData.UpdateZorder();
            AppManager.Edited = true;
            UpdateGridList();
            UpdateObjectList();

            // 再描画を要求
            this.Invalidate();
        }

        private void xmenuFileOutputAbort_Click( object sender, EventArgs e ) {
            if ( !m_avi_cancel ) {
                m_avi_cancel = true;
                AviWriting = false;
                UpdateFormTitle();
            }
        }

        private void xmenuFile_DropDownOpening( object sender, EventArgs e ) {
            bool value = !AviWriting && AppManager.SaveData.m_totalSec > 0.0f;
            xmenuFileOutputAvi.Enabled = value;
            xmenuFileOutputRawAvi.Enabled = value;
            xmenuFileSeriesBitmap.Enabled = value;

            if ( AppManager.SaveData.m_groups_character.Count <= 0 ) {
                xmenuFileExportHatwune.Enabled = false;
                xmenuFileExportVocaloMark.Enabled = false;
            } else {
                xmenuFileExportHatwune.Enabled = true;
                xmenuFileExportVocaloMark.Enabled = true;
            }
        }

        private void xmenuFileExportHatwune_Click( object sender, EventArgs e ) {
            int target = 0;
            if ( AppManager.SaveData.m_groups_character.Count > 1 ) {
                string msg = _( "Specify the index of target character" );
                for ( int i = 0; i < AppManager.SaveData.m_groups_character.Count; i++ ) {
                    msg += "\n" + i + " : " + AppManager.SaveData.m_groups_character[i].Text;
                }
                using ( InputBox dlg = new InputBox( msg, "LipSync" ) ) {
                    if ( dlg.ShowDialog() == DialogResult.OK ) {
                        try {
                            target = int.Parse( dlg.rText );
                        } catch {
                            MessageBox.Show( _( "Invalid value has been entered" ),
                                             _( "Error" ),
                                             MessageBoxButtons.OK,
                                             MessageBoxIcon.Exclamation );
                            return;
                        }
                        if ( target < 0 || AppManager.SaveData.m_groups_character.Count <= target ) {
                            MessageBox.Show( _( "Invalid value has been entered" ),
                                             _( "Error" ),
                                             MessageBoxButtons.OK,
                                             MessageBoxIcon.Exclamation );
                            return;
                        }
                    }
                }
            }
            using ( SaveFileDialog dlg2 = new SaveFileDialog() ) {
                if ( dlg2.ShowDialog() == DialogResult.OK ) {
                    string file = dlg2.FileName;
                    using ( StreamWriter sw = new StreamWriter( file, false, Encoding.GetEncoding( "Shift_JIS" ) ) )
                    using ( TimeTable table = new TimeTable( "", 0, TimeTableType.none, null ) ) {
                        sw.WriteLine( "Init{" );
                        sw.WriteLine( "\tSetFog( 10.0, 180.0, 200, 225, 255 )" );
                        sw.WriteLine( "\tSetGlareFilter( 1.0, 1.0, 1.0, 0.20, -0.81, -0.80, -0.78, 0.0 )" );
                        sw.WriteLine( "\tSetDirectionLight( -1.0, -0.6, -0.4 )" );
                        sw.WriteLine( "\tSetAmbientLight( 1.0, 1.0, 1.0 )" );
                        sw.WriteLine( "\tSetBGColor( 0, 0, 0 )" );
                        sw.WriteLine( "\tLoadStage( \"data\\xsi\\stage01\\\", \"stage01.xsibin\" )" );
                        bool wave_exists = false;
                        if ( Path.GetExtension( AppManager.SaveData.m_audioFile ).ToLower() == ".wav" ) {
                            wave_exists = true;
                            sw.WriteLine( "\tLoadBGM( \"" + Path.GetDirectoryName( AppManager.SaveData.m_audioFile ) + "\", \"" + Path.GetFileName( AppManager.SaveData.m_audioFile ) + "\" )" );
                        }
                        sw.WriteLine( "}" );
                        sw.WriteLine( "Main{" );
                        sw.WriteLine( "\tCamera( 0, Offset, 0, 1.45, 3.2,  0, 1.0, 0, 0, Linear, 0 )" );
                        sw.WriteLine( "\tMotion( 0, GoMyWay, 0, 1.5,  0 )" );
                        if ( wave_exists ) {
                            sw.WriteLine( "	PlayBGM( 1.0 )" );
                        }
                        sw.WriteLine( "\tAppendTriggerUncondition( 1.0, Face_Group )" );
                        sw.WriteLine( "\tEnd( " + (AppManager.SaveData.m_totalSec + 1) + ", Return )" );
                        sw.WriteLine( "}" );
                        sw.WriteLine( "Face_Group{" );

                        // エントリを列挙
                        for ( int track = 0; track < AppManager.SaveData.m_groups_character[target].Count; track++ ) {
                            for ( int entry = 0; entry < AppManager.SaveData.m_groups_character[target][track].Count; entry++ ) {
                                TimeTableEntry ent = AppManager.SaveData.m_groups_character[target][track][entry];
                                table.Add( (TimeTableEntry)ent.Clone() );
                            }
                        }
                        table.Sort();

                        //繋がってる奴は連結させておく
                        bool change = true;
                        while ( change ) {
                            change = false;
                            for ( int entry = 0; entry < table.Count - 1; entry++ ) {
                                if ( table[entry].body == table[entry + 1].body && table[entry].end == table[entry + 1].begin ) {
                                    table[entry].end = table[entry + 1].end;
                                    table.RemoveAt( entry + 1 );
                                    change = true;
                                    break;
                                }
                            }
                        }

                        for ( int entry = 0; entry < table.Count; entry++ ) {
                            string type;
                            float begin = table[entry].begin;
                            float end = table[entry].end;
                            switch ( table[entry].body ) {
                                case "a":
                                    type = "L_A";
                                    break;
                                case "i":
                                    type = "L_I";
                                    break;
                                case "u":
                                    type = "L_U";
                                    break;
                                case "e":
                                    type = "L_E";
                                    break;
                                case "o":
                                case "xo":
                                    type = "L_O";
                                    break;
                                case "nn":
                                    type = "L_Default";
                                    break;
                                default:
                                    type = "";
                                    break;
                            }
                            if ( type != "" ) {
                                bool force_default = true;
                                if ( entry + 1 < table.Count ) {
                                    if ( end == table[entry + 1].begin ) {
                                        force_default = false;
                                    }
                                }

                                if ( force_default ) {
                                    //todo: 0.30より短い場合は？
                                    sw.WriteLine( "\tFace( " + begin + ", " + type + ", " + 0.15 + " )" );
                                    sw.WriteLine( "\tFace( " + (end - 0.15) + ", L_Default, " + 0.15 + " )" );
                                } else {
                                    sw.WriteLine( "\tFace( " + begin + ", " + type + ", " + 0.15 + " )" );
                                }
                            }
                        }
                        sw.WriteLine( "}" );
                    }
                }
            }
        }

        private void xmenuFileExportVocaloMark_Click( object sender, EventArgs e ) {
            using ( FormVocalomark fv = new FormVocalomark( AppManager.SaveData.m_groups_character[0].Character ) ) {
                fv.ShowDialog();
                int target = 0;
                if ( AppManager.SaveData.m_groups_character.Count > 1 ) {
                    string msg = _( "Specify the index of target character" );
                    for ( int i = 0; i < AppManager.SaveData.m_groups_character.Count; i++ ) {
                        msg += "\n" + i + " : " + AppManager.SaveData.m_groups_character[i].Text;
                    }
                    using ( InputBox dlg = new InputBox( msg, "LipSync" ) ) {
                        if ( dlg.ShowDialog() == DialogResult.OK ) {
                            try {
                                target = int.Parse( dlg.rText );
                            } catch {
                                MessageBox.Show( _( "Invalid value has been entered" ),
                                                 _( "Error" ),
                                                 MessageBoxButtons.OK,
                                                 MessageBoxIcon.Exclamation );
                                return;
                            }
                            if ( target < 0 || AppManager.SaveData.m_groups_character.Count <= target ) {
                                MessageBox.Show( _( "Invalid value has been entered" ),
                                                 _( "Error" ),
                                                 MessageBoxButtons.OK,
                                                 MessageBoxIcon.Exclamation );
                                return;
                            }
                        }
                    }
                }
                using ( SaveFileDialog dlg2 = new SaveFileDialog() ) {
                    if ( dlg2.ShowDialog() == DialogResult.OK ) {
                        string file = dlg2.FileName;
                        using ( StreamWriter sw = new StreamWriter( file, false, Encoding.GetEncoding( "Shift_JIS" ) ) )
                        using ( TimeTable table = new TimeTable( "", 0, TimeTableType.none, null ) ) {
                            // エントリを列挙
                            for ( int track = 0; track < AppManager.SaveData.m_groups_character[target].Count; track++ ) {
                                for ( int entry = 0; entry < AppManager.SaveData.m_groups_character[target][track].Count; entry++ ) {
                                    TimeTableEntry ent = AppManager.SaveData.m_groups_character[target][track][entry];
                                    table.Add( (TimeTableEntry)ent.Clone() );
                                }
                            }
                            table.Sort();

                            //繋がってる奴は連結させておく
                            bool change = true;
                            while ( change ) {
                                change = false;
                                for ( int entry = 0; entry < table.Count - 1; entry++ ) {
                                    if ( table[entry].body == table[entry + 1].body && table[entry].end == table[entry + 1].begin ) {
                                        table[entry].end = table[entry + 1].end;
                                        table.RemoveAt( entry + 1 );
                                        change = true;
                                        break;
                                    }
                                }
                            }

                            Dictionary<string, string> dict = new Dictionary<string, string>();
                            foreach ( KeyValuePair<string, string> kvp in fv.Assignment ) {
                                dict.Add( kvp.Value, kvp.Key );
                            }

                            sw.WriteLine( "ShapeAnime_LipSync{" );
                            for ( int i = 0; i < table.Count; i++ ) {
                                if ( dict.ContainsKey( table[i].body ) ) {
                                    string type = dict[table[i].body];
                                    float blend_from_default = 0.05f;
                                    float blend_to_default = 0.05f;
                                    string def = "L_Default";
                                    if ( type.StartsWith( "E_" ) ){
                                        blend_from_default = fv.BlendEyeFromDefault;
                                        blend_to_default = fv.BlendEyeToDefault;
                                        def = "E_Default";
                                    } else if ( type.StartsWith( "EB_" ) ){
                                        blend_from_default = fv.BlendEyebrowFromDefault;
                                        blend_to_default = fv.BlendEyebrowToDefault;
                                        def = "EB_Default";
                                    } else if ( type.StartsWith( "L_" ) ){
                                        blend_from_default = fv.BlendLipFromDefault;
                                        blend_to_default = fv.BlendLipToDefault;
                                    }
                                    sw.WriteLine( "\tSetShape(" + table[i].begin.ToString( "0.000000" ) + ", DefaultUnit, " + type + ", " + blend_from_default.ToString( "0.000000" ) + ")" );
                                    sw.WriteLine( "\tSetShape(" + table[i].end.ToString( "0.000000" ) + ", DefaultUnit, " + def + ", " + blend_to_default.ToString( "0.000000" ) + ")" );
                                    sw.WriteLine();
                                }
                            }
                            sw.WriteLine( "}" );
                        }
                    }
                }
            }
            //todo: Form1+xmenuFileExportVocaloMark_Click
            //ShapeAnime_LipSync
            //{
            //    SetShape(4.195052, DefaultUnit, L_O, 0.1)
            //    SetShape(4.375056, DefaultUnit, L_Default, 0.2)

            //ShapeAnime_Eye
            //{
            //    SetShape(1.945060, DefaultUnit, E_Close, 0.05)
            //    SetShape(2.020068, DefaultUnit, E_Default, 0.05)
            //E_Close
            //E_Default
            //E_Sad
            //E_Serious
            //E_Smile
            //E_Surprise
            //E_WinkL
            //E_WinkR
            //EB_Confuse
            //EB_Default
            //EB_Sad
            //EB_Serious
            //EB_Surprise
            //L_Default
            //L_A
            //L_E
            //L_I
            //L_N
            //L_O
            //L_U
        }

        private void xmenuFileImportRipsync_Click( object sender, EventArgs e ) {
            if ( MessageBox.Show( _( "This operation will overwrite all exisiting time-tables, and can NOT undo. Would you like to continue?" ),
                                  _( "Confirmation" ),
                                  MessageBoxButtons.OKCancel,
                                  MessageBoxIcon.Question ) != DialogResult.OK ) {
                return;
            }
            if ( openRseDialog.ShowDialog() == DialogResult.OK ) {
                string file = openRseDialog.FileName;
                if ( File.Exists( file ) ) {
                    ClearExistingData();
                    RspImporter.Import( file, ref AppManager.SaveData );
                    AppManager.Edited = true;
                    SetVScrollRange();
                    SetHScrollRange();
                    if ( m_player.SoundLocation != "" ) {
                        m_player.Close();
                        AppManager.Playing = false;
                        StopPauseCore();
                        previewer.PlayPauseText = _( "Play" );
                    }
                    m_player.Load( AppManager.SaveData.m_audioFile );
                } else {
                    MessageBox.Show( _( "File not found" ),
                                     _( "Error" ),
                                     MessageBoxButtons.OK,
                                     MessageBoxIcon.Exclamation );
                }
            }
        }

        private void xmenuFileExit_Click( object sender, EventArgs e ) {
            SaveConfig();
            this.Close();
        }

        private void xmenuFileSaveAs_Click( object sender, EventArgs e ) {
            if ( saveFileDialog1.ShowDialog() == DialogResult.OK ) {
                if ( Path.GetExtension( saveFileDialog1.FileName ).ToLower() == ".lse" ) {
                    m_filePath = saveFileDialog1.FileName;
                    Save( m_filePath );
                } else {
                    MessageBox.Show( _( "Extension must be *.lse" ),
                                     _( "Error" ),
                                     MessageBoxButtons.OK,
                                     MessageBoxIcon.Exclamation );
                }
            }
        }

        private void xmenuFileOpen_Click( object sender, EventArgs e ) {
            if ( openLse.ShowDialog() == DialogResult.OK ) {
                Read( openLse.FileName );
                m_filePath = openLse.FileName;
                UpdateFormTitle();
                SetHScrollRange();
                SetVScrollRange();
                AppManager.SaveData.UpdateZorder();
                UpdateObjectList();
                pictureBox1.Invalidate();
            }
        }

        private void xmenuFileSave_Click( object sender, EventArgs e ) {
            if ( m_filePath == "" ) {
                if ( saveFileDialog1.ShowDialog() == DialogResult.OK ) {
                    if ( Path.GetExtension( saveFileDialog1.FileName ).ToLower() == ".lse" ) {
                        m_filePath = saveFileDialog1.FileName;
                        Save( m_filePath );
                    } else {
                        MessageBox.Show( _( "Extension must be *.lse" ),
                                         _( "Error" ),
                                         MessageBoxButtons.OK,
                                         MessageBoxIcon.Exclamation );
                    }
                } else {
                    return;
                }
            } else {
                if ( Path.GetExtension( m_filePath ).ToLower() == ".lse" ) {
                    Save( m_filePath );
                } else {
                    MessageBox.Show( _( "Extension must be *.lse" ),
                                     _( "Error" ),
                                     MessageBoxButtons.OK,
                                     MessageBoxIcon.Exclamation );
                }
            }
        }

        private void xmenuFileSeriesBitmap_Click( object sender, EventArgs e ) {
            using ( FormSeriesImage fsi = new FormSeriesImage() ) {
                if ( fsi.ShowDialog() == DialogResult.OK ) {
                    AviWriting = true;
                    m_avi_cancel = false;
                    AviOutputArguments args = new AviOutputArguments();
                    args.AviFile = fsi.DirectoryName;
                    args.StartSpecified = fsi.StartSpecified;
                    args.EndSpecified = fsi.EndSpecified;
                    args.Start = fsi.Start;
                    args.End = fsi.End;
                    args.FileNameParser = fsi.ParserString;
                    args.ImageFormat = fsi.ImageFormat;
                    bgWorkSeriesImage.RunWorkerAsync( args );
                }
            }
        }
        #endregion

        #region side
        private void side_MouseClick( object sender, MouseEventArgs e ) {
            if ( e.Button == MouseButtons.Left ) {
                int y = e.Y + m_startToDrawY;

                int rows = 1;
                bool vsq_fixed = AppManager.Config.FixVsqTrackPosition;
                // VSQトラック
                if ( vsq_fixed ) {
                    if ( rows * AppManager.Config.TrackHeight <= e.Y && e.Y < (rows + 1) * AppManager.Config.TrackHeight ) {
                        AppManager.SaveData.m_group_vsq.Folded = !AppManager.SaveData.m_group_vsq.Folded;
                        m_vsq_height = AppManager.Config.TrackHeight * (AppManager.SaveData.m_group_vsq.VisibleTracks + 2);
                        SetVScrollRange();
                        this.Invalidate();
                        return;
                    }
                } else {
                    if ( rows * AppManager.Config.TrackHeight <= y && y < (rows + 1) * AppManager.Config.TrackHeight ) {
                        AppManager.SaveData.m_group_vsq.Folded = !AppManager.SaveData.m_group_vsq.Folded;
                        m_vsq_height = AppManager.Config.TrackHeight * (AppManager.SaveData.m_group_vsq.VisibleTracks + 2);
                        SetVScrollRange();
                        this.Invalidate();
                        return;
                    }
                }
                rows++;
                if ( !AppManager.SaveData.m_group_vsq.Folded ) {
                    rows += AppManager.SaveData.m_group_vsq.Count;
                }
                // character
                if ( AppManager.SaveData.m_groups_character.Count > 0 ) {
                    for ( int group = 0; group < AppManager.SaveData.m_groups_character.Count; group++ ) {
                        if ( rows * AppManager.Config.TrackHeight <= y && y < (rows + 1) * AppManager.Config.TrackHeight ) {
                            if ( !vsq_fixed || (vsq_fixed && e.Y >= m_vsq_height) ) {
                                AppManager.SaveData.m_groups_character[group].Folded = !AppManager.SaveData.m_groups_character[group].Folded;
                                SetVScrollRange();
                                m_startToDrawY = StartToDrawY();
                                this.Invalidate();
                                return;
                            }
                        }
                        rows++;
                        if ( !AppManager.SaveData.m_groups_character[group].Folded ) {
                            rows += AppManager.SaveData.m_groups_character[group].Count;
                        }
                    }
                }
                // telop
                if ( rows * AppManager.Config.TrackHeight <= y && y < (rows + 1) * AppManager.Config.TrackHeight ) {
                    if ( !vsq_fixed || (vsq_fixed && e.Y >= m_vsq_height) ) {
                        AppManager.SaveData.TelopListFolded = !AppManager.SaveData.TelopListFolded;
                        SetVScrollRange();
                        m_startToDrawY = StartToDrawY();
                        this.Invalidate();
                        return;
                    }
                }
                rows++;
                if ( !AppManager.SaveData.TelopListFolded ) {
                    rows += AppManager.MaxTelopLanes;
                }
                // another
                if ( rows * AppManager.Config.TrackHeight <= y && y < (rows + 1) * AppManager.Config.TrackHeight ) {
                    if ( !vsq_fixed || (vsq_fixed && e.Y >= m_vsq_height) ) {
                        AppManager.SaveData.m_group_another.Folded = !AppManager.SaveData.m_group_another.Folded;
                        SetVScrollRange();
                        m_startToDrawY = StartToDrawY();
                        this.Invalidate();
                        return;
                    }
                }
                rows++;
                if ( !AppManager.SaveData.m_group_another.Folded ) {
                    rows += AppManager.SaveData.m_group_another.Count;
                }
                // plugin
                if ( rows * AppManager.Config.TrackHeight <= y && y < (rows + 1) * AppManager.Config.TrackHeight ) {
                    if ( !vsq_fixed || (vsq_fixed && e.Y >= m_vsq_height) ) {
                        AppManager.SaveData.m_group_plugin.Folded = !AppManager.SaveData.m_group_plugin.Folded;
                        SetVScrollRange();
                        m_startToDrawY = StartToDrawY();
                        this.Invalidate();
                        return;
                    }
                }
                rows++;
                if ( !AppManager.SaveData.m_group_plugin.Folded ) {
                    rows += AppManager.SaveData.m_group_plugin.Count;
                }
            } else if ( e.Button == MouseButtons.Right ) {
                if ( !cmenu.IsDisposed || cmenu != null ) {
                    cmenu.Dispose();
                }
                cmenu = new ContextMenuStrip();
                cmenu.RenderMode = ToolStripRenderMode.ManagerRenderMode;
                cmenu.ShowCheckMargin = false;
                cmenu.ShowImageMargin = false;
                cmenu.Font = AppManager.Config.Font.GetFont();
                cmenu.Items.Add( _( "Expand All" ), null, new EventHandler( h_expandAll ) );
                cmenu.Items.Add( _( "Fold All" ), null, new EventHandler( h_foldAll ) );
                cmenu.Show( side, new Point( e.X, e.Y ) );
            }
        }

        private void side_Paint( object sender, PaintEventArgs e ) {
            if ( m_skip_paint ) {
                return;
            }
            Graphics g = e.Graphics;
            g.Clear( TOOL_COLOR );
            int rows = 1;
            // VSQトラック
            bool vsq_fixed = AppManager.Config.FixVsqTrackPosition;
            if ( !vsq_fixed ) {
                DrawTriangle( g, rows * AppManager.Config.TrackHeight - m_startToDrawY, AppManager.SaveData.m_group_vsq.Folded );
            }
            rows++;
            if ( !AppManager.SaveData.m_group_vsq.Folded ) {
                rows += AppManager.SaveData.m_group_vsq.Count;
            }

            // character
            if ( AppManager.SaveData.m_groups_character.Count > 0 ) {
                for ( int group = 0; group < AppManager.SaveData.m_groups_character.Count; group++ ) {
                    DrawTriangle( g, rows * AppManager.Config.TrackHeight - m_startToDrawY, AppManager.SaveData.m_groups_character[group].Folded );
                    rows++;
                    if ( !AppManager.SaveData.m_groups_character[group].Folded ) {
                        rows += AppManager.SaveData.m_groups_character[group].Count;
                    }
                }
            }

            // telop
            DrawTriangle( g, rows * AppManager.Config.TrackHeight - m_startToDrawY, AppManager.SaveData.TelopListFolded );
            rows++;
            if ( !AppManager.SaveData.TelopListFolded ) {
                rows += AppManager.MaxTelopLanes;
            }

            // another
            DrawTriangle( g, rows * AppManager.Config.TrackHeight - m_startToDrawY, AppManager.SaveData.m_group_another.Folded );
            rows++;
            if ( !AppManager.SaveData.m_group_another.Folded ) {
                rows += AppManager.SaveData.m_group_another.Count;
            }
            // plugin
            DrawTriangle( g, rows * AppManager.Config.TrackHeight - m_startToDrawY, AppManager.SaveData.m_group_plugin.Folded );
            rows++;
            if ( !AppManager.SaveData.m_group_plugin.Folded ) {
                rows += AppManager.SaveData.m_group_plugin.Count;
            }
            if ( vsq_fixed ) {
                g.FillRectangle(
                    new SolidBrush( TOOL_COLOR ),
                    new Rectangle( 0, 0, side.Width, m_vsq_height ) );
                g.DrawLine(
                    new Pen( Color.Black, 2 ),
                    new Point( 0, m_vsq_height ),
                    new Point( side.Width, m_vsq_height ) );
                DrawTriangle( g, AppManager.Config.TrackHeight, AppManager.SaveData.m_group_vsq.Folded );
            }
        }
        #endregion

        private void SettingsEx_CommandExecuted( TimeTableType command_target, CommandType command_type ) {
#if DEBUG
            Common.DebugWriteLine( "AppManager_CommandExecuted" );
#endif
            if ( command_type == CommandType.deleteEntry ||
                 command_type == CommandType.deleteGroup ||
                 command_type == CommandType.deleteTelop ||
                 command_type == CommandType.deleteTimeTable ) {

            }
            menuEditRedo.Enabled = AppManager.IsRedoAvailable;
            menuEditUndo.Enabled = AppManager.IsUndoAvailable;
            this.Refresh();
        }

        private void previewer_SpeedClicked( object sender, EventArgs e ) {
            previewer.TrackSpeedValue = 1000;
            ChangeSpeed( 1000 );
        }

        #region trackSpeed
        private void previewer_TrackSpeedMouseUp( object sender, MouseEventArgs e ) {
#if DEBUG
            Common.DebugWriteLine( "trackSpeed_MouseUp" );
#endif
            ChangeSpeed( previewer.TrackSpeedValue );
        }

        private void previewer_TrackSpeedScroll( object sender, EventArgs e ) {
            float speed = previewer.TrackSpeedValue * 0.001f;
            previewer.LabelSpeedText = "x" + speed.ToString( "0.00" );
        }
        #endregion

        #region cmenuRepeat
        private void cmenuRepeatStart_Click( object sender, EventArgs e ) {
            AppManager.SaveData.REPEAT_START = SecFromXCoord( m_mousePosition.X );
        }

        private void cmenuRepeatEnd_Click( object sender, EventArgs e ) {
            AppManager.SaveData.REPEAT_END = SecFromXCoord( m_mousePosition.X );
        }

        private void cmenuRepeatReset_Click( object sender, EventArgs e ) {
            AppManager.SaveData.REPEAT_START = 0f;
            AppManager.SaveData.REPEAT_END = -1f;
        }

        private void cmenuRepeat_Opening( object sender, CancelEventArgs e ) {
            float pos = SecFromXCoord( m_mousePosition.X );
            if ( RepeatEnd < pos ) {
                cmenuRepeatStart.Enabled = false;
            } else {
                cmenuRepeatStart.Enabled = true;
            }
            if ( RepeatStart > pos ) {
                cmenuRepeatEnd.Enabled = false;
            } else {
                cmenuRepeatEnd.Enabled = true;
            }
        }
        #endregion

        #region menuVisual*
        private void menuVisualTop_Click( object sender, EventArgs e ) {
            if ( hScrollBar1.Value != hScrollBar1.Minimum ) {
                hScrollBar1.Value = hScrollBar1.Minimum;
                m_startToDrawX = StartToDrawX();
                this.Invalidate();
            }
        }

        private void menuVisualEnd_Click( object sender, EventArgs e ) {
            if ( hScrollBar1.Value != hScrollBar1.Maximum + 1 - hScrollBar1.LargeChange ) {
                hScrollBar1.Value = hScrollBar1.Maximum + 1 - hScrollBar1.LargeChange;
                m_startToDrawX = StartToDrawX();
                this.Invalidate();
            }
        }

        /// <summary>
        /// タイムラインの時間拡大率をリセットします
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void menuVisualZoomReset_Click( object sender, EventArgs e ) {
            AppManager.Config.PixelPerSec = 150.0f;
            SetHScrollRange();
            correctPosition();
            //rebuildDrawing();
            this.Invalidate();
        }

        private void menuVisualZoomOut_Click( object sender, EventArgs e ) {
            if ( AppManager.Config.PixelPerSec >= 20.0f ) {
                AppManager.Config.PixelPerSec -= 10.0f;
                SetHScrollRange();
                correctPosition();
                //rebuildDrawing();
                base.Invalidate();
            }
        }

        private void menuVisualRepeatPlayPause_Click( object sender, EventArgs e ) {
            m_is_repeat_mode = true;
            if ( AppManager.Playing ) {
                Pause();
            } else {
                Play();
            }
        }

        private void menuVisualRepeatTop_Click( object sender, EventArgs e ) {
            m_is_repeat_mode = true;
            if ( AppManager.Playing ) {
                Pause();
                previewer.TrackBarValue = (int)(RepeatStart * AppManager.SaveData.FrameRate);
                Play();
            } else {
                previewer.TrackBarValue = (int)(RepeatStart * AppManager.SaveData.FrameRate);
            }
            this.Invalidate();
        }

        private void menuVisualRepeatEnd_Click( object sender, EventArgs e ) {
            m_is_repeat_mode = true;
            if ( AppManager.Playing ) {
                Pause();
            }
            previewer.TrackBarValue = (int)(RepeatEnd * AppManager.SaveData.FrameRate);
            this.Invalidate();
        }

        private void menuVisualTransform_CheckedChanged( object sender, EventArgs e ) {
            m_curve.Visible = menuVisualTransform.Checked;
        }

        private void menuVisualPlayPause_Click( object sender, EventArgs e ) {
            m_is_repeat_mode = false;
            if ( AppManager.Playing ) {
                Pause();
            } else {
                Play();
            }
        }

        private void menuVisualObjectList_Click( object sender, EventArgs e ) {
            ChangePropertyHidden();
        }

        private void menuVisualZoomIn_Click( object sender, EventArgs e ) {
            AppManager.Config.PixelPerSec += 10.0f;
            SetHScrollRange();
            correctPosition();
            //rebuildDrawing();
            base.Invalidate();
        }

        private void menuVisualPreviewFlipVisible_Click( object sender, EventArgs e ) {
            ChangePreviewHidden();
        }

        private void menuVisualPreviewSeparate_Click( object sender, EventArgs e ) {
            PreviewWindowFlipMode();
        }
        #endregion

        #region menuTool*
        private void menuToolMusic_Click( object sender, EventArgs e ) {
            if ( m_player.SoundLocation != "" ) {
                m_player.Close();
                AppManager.Playing = false;
                StopPauseCore();//timerPreview.Enabled = false;
                previewer.PlayPauseText = _( "Play" );
            }
            openMusicDialog.FileName = AppManager.Config.LastMusicPath;
            try {
                openMusicDialog.Filter = _( "Audio File(*.mp3;*.wav)|*.mp3;*.wav" ) + "|" + _( "All Files(*.*)|*.*" );
            } catch {
                openMusicDialog.Filter = "Audio File(*.mp3;*.wav)|*.mp3;*.wav|All Files(*.*)|*.*";
            }
            if ( openMusicDialog.ShowDialog() == DialogResult.OK ) {
                AppManager.Config.LastMusicPath = openMusicDialog.FileName;
                Command run = Command.GCommandSetMp3( openMusicDialog.FileName );
                AppManager.Register( AppManager.SaveData.Execute( run ) );
                m_player.Load( AppManager.SaveData.m_audioFile );
                AppManager.Edited = true;
            }
        }

        private void menuToolMoveTo_Click( object sender, EventArgs e ) {
            using ( InputBox ib = new InputBox( _( "Go to specified frame" ), _( "please input frame index" ) ) ) {
                if ( ib.ShowDialog() == DialogResult.OK ) {
                    int frame;
                    try {
                        frame = int.Parse( ib.rText.Trim() );
                    } catch {
                        MessageBox.Show( _( "Invalid value has been entered" ),
                                         _( "Error" ),
                                         MessageBoxButtons.OK,
                                         MessageBoxIcon.Exclamation );
                        ib.Dispose();
                        return;
                    }
                    if ( previewer.TrackBarMaximum < frame || frame < previewer.TrackBarMinimum ) {
                        MessageBox.Show( _( "invalid frame index" ),
                                         _( "Error" ),
                                         MessageBoxButtons.OK,
                                         MessageBoxIcon.Exclamation );
                        return;
                    }
                    previewer.TrackBarValue = frame;
                    this.Invalidate();
                }
            }
        }

        private void menuToolQuantize04_Click( object sender, EventArgs e ) {
            AppManager.Config.QuantizeMode = QuantizeMode.q04;
            QuantizeMenuCheckedStateUpdate();
        }

        private void menuToolQuantize08_Click( object sender, EventArgs e ) {
            AppManager.Config.QuantizeMode = QuantizeMode.q08;
            QuantizeMenuCheckedStateUpdate();
        }

        private void menuToolQuantize16_Click( object sender, EventArgs e ) {
            AppManager.Config.QuantizeMode = QuantizeMode.q16;
            QuantizeMenuCheckedStateUpdate();
        }

        private void menuToolQuantize32_Click( object sender, EventArgs e ) {
            AppManager.Config.QuantizeMode = QuantizeMode.q32;
            QuantizeMenuCheckedStateUpdate();
        }

        private void menuToolQuantize64_Click( object sender, EventArgs e ) {
            AppManager.Config.QuantizeMode = QuantizeMode.q64;
            QuantizeMenuCheckedStateUpdate();
        }

        private void menuToolQuantizeOff_Click( object sender, EventArgs e ) {
            AppManager.Config.QuantizeMode = QuantizeMode.off;
            QuantizeMenuCheckedStateUpdate();
        }

        private void menuToolQuantizeTriplet_CheckedChanged( object sender, EventArgs e ) {
            AppManager.Config.QuantizeTripletEnabled = menuToolQuantizeTriplet.Checked;
            UpdateGridList();
        }

        private void menuToolOption_Click( object sender, EventArgs e ) {
            using ( EnvConfiguration env = new EnvConfiguration( AppManager.Config ) ) {
                if ( env.ShowDialog() == DialogResult.OK ) {
                    // language
                    AppManager.Config = null;
                    AppManager.Config = (EnvSettings)env.EnvSettings.Clone();

                    ApplyFont( AppManager.Config.Font.GetFont() );
                    property.UpdateLayout();
                    if ( m_curve != null ) {
                        m_curve.ApplyFont( AppManager.Config.Font.GetFont() );
                    }
                    if ( m_version_form != null ) {
                        m_version_form.Font = AppManager.Config.Font.GetFont();
                    }
                    if ( m_form_preview != null ) {
                        m_form_preview.ApplyFont( AppManager.Config.Font.GetFont() );
                    }

                    string lang = AppManager.Config.Language;
                    string[] t_list = Messaging.GetRegisteredLanguage();
                    bool found = false;
                    foreach ( string lng in t_list ) {
                        if ( lng == lang ) {
                            AppManager.Config.Language = lng;
                            Messaging.Language = lng;
                            found = true;
                            break;
                        }
                    }
                    if ( !found ) {
                        AppManager.Config.Language = "";
                        Messaging.Language = "";
                    }
                    ApplyLanguage();
                    UpdateFormTitle();
                    this.Invalidate();
                }
            }
        }
        #endregion

        private void previewer_PlayPauseClicked( object sender, EventArgs e ) {
            m_is_repeat_mode = false;
            if ( AppManager.Playing ) {
                Pause();
            } else {
                Play();
            }
        }

        private void previewer_StopClicked( object sender, EventArgs e ) {
            StopMusic();
        }

        private void previewer_CheckMuteCheckedChanged( object sender, EventArgs e ) {
            if ( previewer.CheckMuteChecked ) {
                m_player.IsMuted = true;
            } else {
                m_player.IsMuted = false;
            }
        }

        private void previewer_TrackVolumeScroll( object sender, EventArgs e ) {
            int volume = previewer.TrackVolumeValue;
            m_player.Volume = volume;
        }

        #region previewer
        private void previewer_PreviewMouseDown( object sender, MouseEventArgs e ) {
#if DEBUG
            Common.DebugWriteLine( "PreviewP_MouseDown" );
#endif
            if ( AppManager.Playing || AviWriting ) {
                return;
            }

            timerScreenUpdater.Enabled = true;
            // オブジェクトのzオーダー順に、クリックされた位置に
            // 表示されているオブジェクトが何かを検索する
            float now = Now;

            //最初にテロップを検索
            foreach ( Telop telop in AppManager.SaveData.m_telop_ex2 ) {
                if ( telop.Start <= now && now <= telop.End ) {
                    m_editing = new EditingBounds( CRectFromIRect( new Rectangle( Common.PointFromPointF( telop.GetPosition( now ) ), 
                                                                                  Common.SizeFromSizeF( telop.ImageSize ) ),
                                                                   telop.GetScale( now ) ),
                                                   telop.PositionFixed,
                                                   telop.IsXFixedAt( now ),
                                                   telop.IsYFixedAt( now ) );
#if DEBUG
                    Common.DebugWriteLine( "    telop.ImageSize=" + telop.ImageSize );
                    Common.DebugWriteLine( "    m_editing.Bounds=" + m_editing.Bounds );
#endif
                    if ( AppManager.IsInRectangle( e.Location, m_editing.Bounds ) ) {
                        ZorderItem zi = new ZorderItem( telop.Text, ZorderItemType.telop, telop.ID );
                        property.Editing = (ZorderItem)zi.Clone();
                        if ( !telop.PositionFixed ) {
                            m_editing_item = zi;
                            m_init_position = Common.PointFromPointF( telop.Position );
                            m_base_point = ICoordFromC( e.Location );
                        }
                        return;
                    }
                }
            }

            bool found = false;
            for ( int i = AppManager.SaveData.m_zorder.Count - 1; i >= 0; i-- ) {
                #region s.m_zorderを検索
                ZorderItem item = AppManager.SaveData.m_zorder[i];
                switch ( item.Type ) {
                    case ZorderItemType.another:
                        for ( int entry = 0; entry < AppManager.SaveData.m_group_another[item.Index].Count; entry++ ) {
                            TimeTable table = AppManager.SaveData.m_group_another[item.Index];
                            if ( table[entry].begin <= now && now <= table[entry].end ) {
                                if ( table.IsAviMode ||
                                    (!table.IsAviMode && table.Image != null) ) {
                                    m_editing = new EditingBounds( CRectFromIRect( new Rectangle( Common.PointFromPointF( table.GetPosition( now ) ),
                                                                                                  table.ImageSize ),
                                                                                   Math.Abs( table.GetScale( now ) ) ),
                                                                   table.PositionFixed,
                                                                   table.IsXFixedAt( now ),
                                                                   table.IsYFixedAt( now ) );
                                    if ( AppManager.IsInRectangle( e.Location, m_editing.Bounds ) ) {
                                        if ( !table.PositionFixed ) {
                                            m_editing_item = item;
                                            m_init_position = Common.PointFromPointF( table.Position );
                                        }
                                        property.Editing = (ZorderItem)item.Clone();
                                        found = true;
                                        break;
                                    }
                                }
                                m_editing = new EditingBounds();
                            } else {
                                break;
                            }
                        }
                        break;
                    case ZorderItemType.character:
                        TimeTableGroup table_group = AppManager.SaveData.m_groups_character[item.Index];
                        string[] spl = table_group.GetDrawObjectNames( now );
                        if ( spl.Length > 0 ) {
                            m_editing = new EditingBounds( CRectFromIRect( new Rectangle( Common.PointFromPointF( table_group.GetPosition( now ) ), 
                                                                                          table_group.Character.Size ),
                                                                           Math.Abs( table_group.GetScale( now ) ) ),
                                                           table_group.PositionFixed,
                                                           table_group.IsXFixedAt( now ),
                                                           table_group.IsYFixedAt( now ) );
                            if ( AppManager.IsInRectangle( e.Location, m_editing.Bounds ) ) {
                                if ( !table_group.PositionFixed ) {
                                    m_editing_item = item;
                                    m_init_position = Common.PointFromPointF( table_group.GetPosition( now ) );
                                }
                                property.Editing = (ZorderItem)item.Clone();
                                found = true;
                                break;
                            }
                            m_editing = new EditingBounds();
                        }
                        break;
                }
                #endregion
                if ( found ) {
                    m_base_point = ICoordFromC( e.Location );
                    break;
                }
            }

            if ( !found ) {
                m_editing = new EditingBounds();
                if ( m_text_edit && m_text != null ) {
                    int id = m_text_id;
                    Telop item = (Telop)AppManager.SaveData[id].Clone();
                    item.Text = m_text.Text;
                    Command run = Command.GCommandEditTelop( id, item );
                    AppManager.Register( AppManager.SaveData.Execute( run ) );
                    AppManager.Edited = true;
                    m_text.Dispose();
                    m_text = null;
                }
                m_text_edit = false;
                m_editing_item = null;
            }
            this.Invalidate();
        }

        private void previewer_PreviewMouseMove( object sender, MouseEventArgs e ) {
            if ( m_editing_item != null ) {
#if DEBUG
                Common.DebugWriteLine( "PreviewP_MouseMove" );
#endif
                float now = Now;
                Point iCurrent = ICoordFromC( e.Location );
                int index = m_editing_item.Index;

                Point new_point = new Point( m_init_position.X + (iCurrent.X - m_base_point.X),
                                             m_init_position.Y + (iCurrent.Y - m_base_point.Y) );
                switch ( m_editing_item.Type ) {
                    case ZorderItemType.telop:
                        if ( !m_text_edit ) {
                            Telop telop = AppManager.SaveData[index];
                            telop.Position = new_point;
                            m_editing = new EditingBounds( CRectFromIRect( new Rectangle( Common.PointFromPointF( telop.GetPosition( now ) ),
                                                                                          Common.SizeFromSizeF( telop.ImageSize ) ),
                                                                           telop.GetScale( now ) ),
                                                           telop.PositionFixed,
                                                           telop.IsXFixedAt( now ),
                                                           telop.IsYFixedAt( now ) );
                        }
                        break;
                    case ZorderItemType.another:
                        TimeTable table = AppManager.SaveData.m_group_another[index];
                        table.Position = new_point;
                        m_editing = new EditingBounds( CRectFromIRect( new Rectangle( Common.PointFromPointF( table.GetPosition( now ) ),
                                                                                      Common.SizeFromSizeF( table.ImageSize ) ),
                                                                       Math.Abs( table.GetScale( now ) ) ),
                                                       table.PositionFixed,
                                                       table.IsXFixedAt( now ),
                                                       table.IsYFixedAt( now ) );
                        break;
                    case ZorderItemType.character:
#if DEBUG
                        Common.DebugWriteLine( "    new_point=" + new_point );
#endif
                        TimeTableGroup table_group = AppManager.SaveData.m_groups_character[index];
                        table_group.Position = new_point;
                        m_editing = new EditingBounds( CRectFromIRect( new Rectangle( Common.PointFromPointF( table_group.GetPosition( now ) ),
                                                                                      Common.SizeFromSizeF( table_group.Character.Size ) ),
                                                                       Math.Abs( table_group.GetScale( now ) ) ),
                                                       table_group.PositionFixed,
                                                       table_group.IsXFixedAt( now ),
                                                       table_group.IsYFixedAt( now ) );
                        break;
                }
                previewer.Invalidate();
            }
        }

        private void previewer_PreviewMouseUp( object sender, MouseEventArgs e ) {
            timerScreenUpdater.Enabled = false;
#if DEBUG
            Common.DebugWriteLine( "PreviewP_MouseUp" );
#endif
            if ( m_editing_item != null ) {
                bool found = false;
                int index = m_editing_item.Index;
                Point new_pos;
                switch ( m_editing_item.Type ) {
                    case ZorderItemType.telop:
                        new_pos = AppManager.SaveData[index].Position;
                        if ( new_pos.X != m_init_position.X || new_pos.Y != m_init_position.Y ) {
                            Command run = Command.GCommandEditTelop( index, AppManager.SaveData[index] );
                            AppManager.SaveData[index].Position = m_init_position;
                            AppManager.Register( AppManager.SaveData.Execute( run ) );
                            property.Editing = new ZorderItem( "", ZorderItemType.telop, index );
                            AppManager.Edited = true;
                        }
                        found = true;
                        break;
                    case ZorderItemType.another:
                        new_pos = AppManager.SaveData.m_group_another[index].Position;
                        if ( new_pos.X != m_init_position.X || new_pos.Y != m_init_position.Y ) {
                            Command run = Command.GCommandSetPosition( TimeTableType.another, -1, index, AppManager.SaveData.m_group_another[index].Position );
                            AppManager.SaveData.m_group_another[index].Position = m_init_position;
                            AppManager.Register( AppManager.SaveData.Execute( run ) );
                            property.Editing = new ZorderItem( "", ZorderItemType.another, index );
                            AppManager.Edited = true;
                        } else {
                            AppManager.SaveData.m_group_another[index].Position = m_init_position;
                        }
                        found = true;
                        break;
                    case ZorderItemType.character:
                        new_pos = AppManager.SaveData.m_groups_character[index].Position;
#if DEBUG
                        Common.DebugWriteLine( "    new_pos=" + new_pos.ToString() );
                        Common.DebugWriteLine( "    m_init_position=" + m_init_position );
                        Common.DebugWriteLine( "    AppManager.SaveData.m_groups_character[index].Position=" + AppManager.SaveData.m_groups_character[index].Position );
#endif
                        if ( new_pos.X != m_init_position.X || new_pos.Y != m_init_position.Y ) {
                            Command run = Command.GCommandSetPosition( TimeTableType.character, index, -1, AppManager.SaveData.m_groups_character[index].Position );
                            AppManager.SaveData.m_groups_character[index].Position = m_init_position;
                            AppManager.Register( AppManager.SaveData.Execute( run ) );
                            property.Editing = new ZorderItem( "", ZorderItemType.character, index );
                            AppManager.Edited = true;
                        } else {
                            AppManager.SaveData.m_groups_character[index].Position = m_init_position;
                        }
                        found = true;
                        break;
                }

                if ( found ) {
                    m_editing_item = null;
                    this.Invalidate();
                    return;
                }
            }
        }

        private void previewer_PreviewMouseDoubleClick( object sender, MouseEventArgs e ) {
#if DEBUG
            Common.DebugWriteLine( "PreviewP_MouseDoubleClick" );
#endif
            if ( m_editing_item != null ) {
                if ( m_editing_item.Type == ZorderItemType.telop ) {
                    Telop item = AppManager.SaveData[m_editing_item.Index];
                    m_text_edit = true;
                    m_text = new TextBox();
                    m_text.Visible = false;
                    m_text.Text = item.Text;
                    m_text_original = item.Text;
                    m_text_id = m_editing_item.Index;
                    Rectangle rc_telop = new Rectangle( Common.PointFromPointF( item.Position ), Common.SizeFromSizeF( item.ImageSize ) );
                    float dum_x, dum_y, scale;
                    GetScaleAndOrigin( out dum_x, out dum_y, out scale );
                    Rectangle rc_text = CRectFromIRect( rc_telop, scale );
                    m_text.Parent = previewer.Preview;
                    m_text.Location = new Point( (int)(rc_text.Left + 1 * scale), (int)(rc_text.Top - 3 * scale) );
                    m_text.Font = new Font( item.Font.FontFamily, item.Font.Size * scale, item.Font.Style );
                    m_text.Multiline = true;
                    m_text.Size = m_text.PreferredSize;
                    m_text.Tag = m_text.Size.Width;
                    m_text.ImeMode = ImeMode.NoControl;
                    m_text.TextChanged += new EventHandler( m_text_TextChanged );
                    m_text.Show();
                    m_text.BringToFront();
                    m_text.Visible = true;
                    m_text.Focus();
                }
            }
        }

        private void previewer_PreviewSizeChanged( object sender, EventArgs e ) {
            UpdateEditHandle();
        }

        private void previewer_PreviewPaint( object sender, PaintEventArgs e ) {
            if ( !m_avi_writing ) {
                using ( Graphics g = Graphics.FromImage( previewer.Image ) ) {
                    string mouth = "";
                    if ( menuEditRealTime.Checked ) {
                        if ( m_last_key == Keys.A ) {
                            mouth = "a";
                        } else if ( m_last_key == Keys.I ) {
                            mouth = "i";
                        } else if ( m_last_key == Keys.U ) {
                            mouth = "u";
                        } else if ( m_last_key == Keys.E ) {
                            mouth = "e";
                        } else if ( m_last_key == Keys.O ) {
                            mouth = "o";
                        }
                    }
                    AppManager.SaveData.DrawTo( g, AppManager.SaveData.m_movieSize, Now, false, mouth, m_realtime_group );
                }
                bool pos_fixed = m_editing.Fixed || (m_editing.XFixed && m_editing.YFixed);
                if ( pos_fixed ) {
                    e.Graphics.DrawRectangle( _PEN_FIXED_BOUNDS, m_editing.Bounds );
                } else {
                    int x = m_editing.Bounds.X;
                    int y = m_editing.Bounds.Y;
                    int width = m_editing.Bounds.Width;
                    int height = m_editing.Bounds.Height;
                    int pen_width = (int)(_PEN_FIXED_BOUNDS.Width / 2f);
#if DEBUG
                    //Common.DebugWriteLine( "previewer_PreviewPaint" );
                    //Common.DebugWriteLine( "    m_editing.XFixed=" + m_editing.XFixed );
                    //Common.DebugWriteLine( "    m_Editing.YFixed=" + m_editing.YFixed );
#endif
                    if ( m_editing.XFixed ) {
                        e.Graphics.DrawLine( _PEN_FIXED_BOUNDS,
                                             new Point( x, y - pen_width ),
                                             new Point( x, y + height + pen_width ) );
                        e.Graphics.DrawLine( _PEN_FIXED_BOUNDS,
                                             new Point( x + width, y - pen_width ),
                                             new Point( x + width, y + height + pen_width ) );
                        e.Graphics.DrawLine( _PEN_BOUNDS,
                                              new Point( x + pen_width, y ),
                                              new Point( x - pen_width + width, y ) );
                        e.Graphics.DrawLine( _PEN_BOUNDS, 
                                             new Point( x + pen_width, y + height ),
                                             new Point( x - pen_width + width, y + height ) );
                    } else if ( m_editing.YFixed ){
                        e.Graphics.DrawLine( _PEN_BOUNDS,
                                             new Point( x, y + pen_width ),
                                             new Point( x, y - pen_width + height ) );
                        e.Graphics.DrawLine( _PEN_BOUNDS,
                                             new Point( x + width, y + pen_width ),
                                             new Point( x + width, y - pen_width + height ) );
                        e.Graphics.DrawLine( _PEN_FIXED_BOUNDS,
                                              new Point( x - pen_width, y ),
                                              new Point( x + pen_width + width, y ) );
                        e.Graphics.DrawLine( _PEN_FIXED_BOUNDS,
                                             new Point( x - pen_width, y + height ),
                                             new Point( x + pen_width + width, y + height ) );
                    } else {
                        e.Graphics.DrawRectangle( _PEN_BOUNDS, m_editing.Bounds );
                    }
                }
            }
        }
        #endregion

        private void previewer_TrackBarScroll( object sender, EventArgs e ) {
            if ( menuVisualSync.Checked ) {
                correctPosition();
            }
            this.Invalidate();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void previewer_MenuHundredClick( object sender, EventArgs e ) {
            previewer.PreviewSizeMode = PictureBoxSizeMode.CenterImage;
            AppManager.Config.PreviewZoomMode = previewer.PreviewSizeMode;
        }

        private void previewer_MenuFitClick( object sender, EventArgs e ) {
            previewer.PreviewSizeMode = PictureBoxSizeMode.Zoom;
            AppManager.Config.PreviewZoomMode = previewer.PreviewSizeMode;
        }

        private void previewer_LabelTimeMouseDoubleClick( object sender, EventArgs e ) {
            PreviewWindowFlipMode();
        }

        private void m_container_Panel2_SizeChanged( object sender, EventArgs e ) {
            ResizePanel2();
        }

        #region bgWorkSeriesImage
        private void bgWorkSeriesImage_DoWork( object sender, DoWorkEventArgs e ) {
            Size size = AppManager.SaveData.m_movieSize;
            m_avi_cancel = false;

            long start_frame;
            AviOutputArguments args = (AviOutputArguments)e.Argument;
            bool is_raw_mode = args.IsRawMode;
            if ( args.StartSpecified ) {
                start_frame = (long)(args.Start * AppManager.SaveData.FrameRate);
            } else {
                start_frame = 0L;
            }

            long end_frame;
            if ( args.EndSpecified ) {
                end_frame = (long)(args.End * AppManager.SaveData.FrameRate);
            } else {
                end_frame = (long)((AppManager.SaveData.m_totalSec) * AppManager.SaveData.FrameRate);
            }
            long total_frames = end_frame - start_frame + 1;
#if !DEBUG
            try {
#endif
            long count = -1;
            for ( long frame = start_frame; frame <= end_frame; frame++ ) {
                count++;
                float now = (float)frame / AppManager.SaveData.FrameRate;
                Bitmap frm = GetPicture( now, false );
                try {
                    string file = Path.Combine( args.AviFile, string.Format( args.FileNameParser, count ) );
                    frm.Save( file, args.ImageFormat );
                } catch ( Exception ex ) {
#if DEBUG
                    Common.LogPush( ex );
#endif
                    this.Invoke( new Form1_AviWritingChange( ChangeAviWriting ), new object[] { false } );
                    return;
                }
                bgWorkSeriesImage.ReportProgress( (int)((double)(frame - start_frame) / (double)(total_frames) * 100.0), new long[] { frame - start_frame, total_frames } );
                if ( m_avi_cancel ) {
                    m_avi_cancel = false;
                    return;
                }
            }
#if !DEBUG
            } catch {
            }
#endif
        }

        private void bgWorkSeriesImage_ProgressChanged( object sender, ProgressChangedEventArgs e ) {
            long[] stat = (long[])e.UserState;
            this.Text = _( "Series Image Progress" ) + " " + e.ProgressPercentage + "%  [" + stat[0] + "/" + stat[1] + "]";
        }

        private void bgWorkSeriesImage_RunWorkerCompleted( object sender, RunWorkerCompletedEventArgs e ) {
            this.Invoke( new Form1_AviWritingChange( ChangeAviWriting ), new object[] { false } );
            m_avi_cancel = false;
            UpdateFormTitle();
        }
        #endregion

        private void timerScreenUpdater_Tick( object sender, EventArgs e ) {
            previewer.Invalidate();
        }

        private void menuVisualVsqTrack_CheckedChanged( object sender, EventArgs e ) {
            AppManager.Config.FixVsqTrackPosition = menuVisualVsqTrack.Checked;
        }
    }

}
