2 using System.Collections.Generic;
3 using System.Diagnostics;
7 using System.Reflection;
8 using System.Windows.Forms;
9 using FDK; // for string拡張
13 partial class メインフォーム : Form
15 public int メジャーバージョン番号 => ( Assembly.GetExecutingAssembly().GetName().Version.Major );
16 public int マイナーバージョン番号 => ( Assembly.GetExecutingAssembly().GetName().Version.Minor );
17 public int リビジョン番号 => ( Assembly.GetExecutingAssembly().GetName().Version.Revision );
18 public int ビルド番号 => ( Assembly.GetExecutingAssembly().GetName().Version.Build );
20 public const int 最大音量 = 4;
21 public const int 最小音量 = 1;
27 return this.bs_未保存である;
32 this.bs_未保存である = value;
34 // ウィンドウのタイトルバーの文字列を修正する。
35 string 表示するファイルの名前 = ( string.IsNullOrEmpty( this.編集中のファイル名 ) ) ? Properties.Resources.NEW_FILENAME : this.編集中のファイル名;
38 // 変更ありかつ未保存なら「*」を付ける。
39 this.Text = $"SSTFEditor {this.メジャーバージョン番号}.{this.マイナーバージョン番号}.{this.リビジョン番号}.{this.ビルド番号} *[{表示するファイルの名前}]";
40 this.toolStripMenuItem上書き保存.Enabled = true;
41 this.toolStripButton上書き保存.Enabled = true;
45 // 保存後変更がないなら「*」は付けない。
46 this.Text = $"SSTFEditor {this.メジャーバージョン番号}.{this.マイナーバージョン番号}.{this.リビジョン番号}.{this.ビルド番号} [{表示するファイルの名前}]";
47 this.toolStripMenuItem上書き保存.Enabled = false;
48 this.toolStripButton上書き保存.Enabled = false;
52 public bool 選択モードである => ( ( CheckState.Checked == this.toolStripButton選択モード.CheckState ) ? true : false );
53 public bool 編集モードである => ( ( CheckState.Checked == this.toolStripButton編集モード.CheckState ) ? true : false );
55 public int GRID_PER_PART { get; protected set; }
56 public int GRID_PER_PIXEL => ( this.bs_GRID_PER_PIXEL / ( this.toolStripComboBox譜面拡大率.SelectedIndex + 1 ) );
58 public bool 初期化完了 = false;
63 public UndoRedo.管理 UndoRedo管理;
64 public クリップボード クリップボード;
65 public Size 譜面パネルサイズ => ( this.pictureBox譜面パネル.ClientSize );
66 public SSTFormat.チップ種別 現在のチップ種別
70 return this.bs_e現在のチップ種別;
74 this.bs_e現在のチップ種別 = value;
75 this.label現在のチップ種別.Text = this.チップ種別toチップ名対応表[ value ];
78 public int 現在のチップ音量 = メインフォーム.最大音量;
82 InitializeComponent();
87 public void 選択モードに切替えて関連GUIを設定する()
89 this.toolStripButton選択モード.CheckState = CheckState.Checked;
90 this.toolStripButton編集モード.CheckState = CheckState.Unchecked;
92 this.toolStripMenuItem選択モード.CheckState = CheckState.Checked;
93 this.toolStripMenuItem編集モード.CheckState = CheckState.Unchecked;
95 this.label現在のチップ種別.Text = "----";
99 public void 編集モードに切替えて関連GUIを設定する()
101 this.選択モード.全チップの選択を解除する();
104 this.toolStripButton選択モード.CheckState = CheckState.Unchecked;
105 this.toolStripButton編集モード.CheckState = CheckState.Checked;
107 this.toolStripMenuItem選択モード.CheckState = CheckState.Unchecked;
108 this.toolStripMenuItem編集モード.CheckState = CheckState.Checked;
110 public void 選択チップの有無に応じて編集用GUIのEnabledを設定する()
112 bool 譜面上に選択チップがある = this.選択チップが1個以上ある;
113 bool クリップボードに選択チップがある = ( null != this.クリップボード ) && ( 0 < this.クリップボード.セル数 );
115 // 編集メニューの Enabled 設定
116 this.toolStripMenuItemコピー.Enabled = 譜面上に選択チップがある;
117 this.toolStripMenuItem切り取り.Enabled = 譜面上に選択チップがある;
118 this.toolStripMenuItem貼り付け.Enabled = クリップボードに選択チップがある;
119 this.toolStripMenuItem削除.Enabled = 譜面上に選択チップがある;
122 this.toolStripButtonコピー.Enabled = 譜面上に選択チップがある;
123 this.toolStripButton切り取り.Enabled = 譜面上に選択チップがある;
124 this.toolStripButton貼り付け.Enabled = クリップボードに選択チップがある;
125 this.toolStripButton削除.Enabled = 譜面上に選択チップがある;
128 this.toolStripMenuItem選択チップのコピー.Enabled = 譜面上に選択チップがある;
129 this.toolStripMenuItem選択チップの切り取り.Enabled = 譜面上に選択チップがある;
130 this.toolStripMenuItem選択チップの貼り付け.Enabled = クリップボードに選択チップがある;
131 this.toolStripMenuItem選択チップの削除.Enabled = 譜面上に選択チップがある;
133 public void 譜面をリフレッシュする()
135 this.pictureBox譜面パネル.Refresh();
137 public void UndoRedo用GUIのEnabledを設定する()
139 bool Undo可 = ( 0 < this.UndoRedo管理.Undo可能な回数 ) ? true : false;
140 bool Redo可 = ( 0 < this.UndoRedo管理.Redo可能な回数 ) ? true : false;
142 this.toolStripMenuItem元に戻す.Enabled = Undo可;
143 this.toolStripMenuItemやり直す.Enabled = Redo可;
144 this.toolStripButton元に戻す.Enabled = Undo可;
145 this.toolStripButtonやり直す.Enabled = Redo可;
147 public void 選択モードのコンテクストメニューを表示する( int x, int y )
149 this.contextMenuStrip譜面右メニュー.Show( this.pictureBox譜面パネル, x, y );
151 // メニューを表示した時のマウス座標を控えておく。
152 this.選択モードのコンテクストメニューを開いたときのマウスの位置 = new Point( x, y );
154 public void 譜面を縦スクロールする( int nスクロール量grid )
156 int 現在の位置grid = this.vScrollBar譜面用垂直スクロールバー.Value;
157 int スクロール後の位置grid = this.vScrollBar譜面用垂直スクロールバー.Value + nスクロール量grid;
158 int 最小値grid = this.vScrollBar譜面用垂直スクロールバー.Minimum;
159 int 最大値grid = ( this.vScrollBar譜面用垂直スクロールバー.Maximum + 1 ) - this.vScrollBar譜面用垂直スクロールバー.LargeChange;
161 if( スクロール後の位置grid < 最小値grid )
163 スクロール後の位置grid = 最小値grid;
165 else if( スクロール後の位置grid > 最大値grid )
167 スクロール後の位置grid = 最大値grid;
170 this.vScrollBar譜面用垂直スクロールバー.Value = スクロール後の位置grid;
173 protected readonly Dictionary<SSTFormat.チップ種別, string> チップ種別toチップ名対応表 = new Dictionary<SSTFormat.チップ種別, string>() {
176 { SSTFormat.チップ種別.Bass, "BassDrum" },
177 { SSTFormat.チップ種別.BPM, "BPM" },
178 { SSTFormat.チップ種別.China, "China" },
179 { SSTFormat.チップ種別.HiHat_Close, "HiHat(Close)" },
180 { SSTFormat.チップ種別.HiHat_Foot, "FootPedal" },
181 { SSTFormat.チップ種別.HiHat_HalfOpen, "HiHat(HarfOpen)" },
182 { SSTFormat.チップ種別.HiHat_Open, "HiHat(Open)" },
183 { SSTFormat.チップ種別.LeftCrash, "Crash" },
184 { SSTFormat.チップ種別.Ride, "Ride" },
185 { SSTFormat.チップ種別.Ride_Cup, "Ride(Cup)" },
186 { SSTFormat.チップ種別.RightCrash, "Crash" },
187 { SSTFormat.チップ種別.Snare, "Snare" },
188 { SSTFormat.チップ種別.Snare_ClosedRim, "Snare(CloseRimShot)" },
189 { SSTFormat.チップ種別.Snare_Ghost, "Snare(Ghost)" },
190 { SSTFormat.チップ種別.Snare_OpenRim, "Snare(OpenRimShot)" },
191 { SSTFormat.チップ種別.Splash, "Splash" },
192 { SSTFormat.チップ種別.Tom1, "HighTom" },
193 { SSTFormat.チップ種別.Tom1_Rim, "HighTom(RimShot)" },
194 { SSTFormat.チップ種別.Tom2, "LowTom" },
195 { SSTFormat.チップ種別.Tom2_Rim, "LowTom(RimShot)" },
196 { SSTFormat.チップ種別.Tom3, "FloorTom" },
197 { SSTFormat.チップ種別.Tom3_Rim, "FloorTom(RimShot)" },
198 { SSTFormat.チップ種別.Unknown, "" },
199 { SSTFormat.チップ種別.小節線, "" },
200 { SSTFormat.チップ種別.背景動画, "" },
201 { SSTFormat.チップ種別.拍線, "" },
202 { SSTFormat.チップ種別.小節メモ, "" },
206 protected bool 選択チップが1個以上ある
210 if( ( null != this.譜面.SSTFormatScore ) &&
211 ( null != this.譜面.SSTFormatScore.チップリスト ) &&
212 ( 0 < this.譜面.SSTFormatScore.チップリスト.Count ) )
214 foreach( var chip in this.譜面.SSTFormatScore.チップリスト )
223 protected int 現在のガイド間隔 = 0;
224 protected Point 選択モードのコンテクストメニューを開いたときのマウスの位置;
226 private bool bs_未保存である = false;
227 private SSTFormat.チップ種別 bs_e現在のチップ種別;
228 private int bs_GRID_PER_PIXEL = 1;
231 /// SSTFEditor.exe と StrokeStyleT.exe が格納されているフォルダへのパス。
233 protected string システムフォルダパス => ( Path.GetDirectoryName( Application.ExecutablePath ) );
235 /// Windowsログインユーザのアプリデータフォルダ。
239 /// 例: "C:\Users\ログインユーザ名\ApplicationData\SSTFEditor\"
241 protected string ユーザフォルダパス
245 var path = Path.Combine( Environment.GetFolderPath( Environment.SpecialFolder.ApplicationData, Environment.SpecialFolderOption.Create ), @"SSTFEditor\" );
247 if( false == Directory.Exists( path ) )
248 Directory.CreateDirectory( path ); // なければ作成する。
253 protected string 作業フォルダパス = null;
254 protected string 編集中のファイル名 = null;
255 protected string 最後にプレイヤーに渡した一時ファイル名 = null;
257 // アクションメソッド(機能ツリーの最上位。メニューやコマンドバーなどから呼び出される。)
259 protected void Actアプリを起動する()
261 this.GRID_PER_PART = int.Parse( Properties.Resources.GRID_PER_PART );
262 this.bs_GRID_PER_PIXEL = int.Parse( Properties.Resources.GRID_PER_PIXEL );
264 // 作業フォルダの初期値は、Windowsユーザのマイドキュメントフォルダ。
265 this.作業フォルダパス = Environment.GetFolderPath( Environment.SpecialFolder.MyDocuments );
268 this.Config = Config.読み込む( Path.Combine( this.ユーザフォルダパス, Properties.Resources.CONFIG_FILE_NAME ) );
269 if( this.Config.ViewerPath.Nullまたは空である() )
271 // 既定のプレイヤーは、exe と同じ場所にあるものとする。
272 this.Config.ViewerPath = Path.Combine( this.システムフォルダパス, Properties.Resources.PLAYER_NAME );
274 if( false == File.Exists( this.Config.ViewerPath ) )
275 this.Config.ViewerPath = ""; // ビュアーが存在してない。
278 // デザイナでは追加できないイベントを手動で追加する。
279 this.splitContainer分割パネルコンテナ.MouseWheel += new MouseEventHandler( splitContainer分割パネルコンテナ_MouseWheel );
282 this.ConfigのRecentUsedFilesをファイルメニューへ追加する();
286 this.Actガイド間隔を変更する( 16 ); // 初期は 1/16 間隔。
287 this.Act譜面拡大率を変更する( 1 ); // 初期は 標準。
292 protected void Actアプリを終了する()
294 // 一時ファイルが残っていれば、削除する。
295 if( File.Exists( this.最後にプレイヤーに渡した一時ファイル名 ) )
296 File.Delete( this.最後にプレイヤーに渡した一時ファイル名 );
299 this.Config.保存する( Path.Combine( this.ユーザフォルダパス, Properties.Resources.CONFIG_FILE_NAME ) );
301 FDK.Utilities.解放する( ref this.譜面 );
302 FDK.Utilities.解放する( ref this.選択モード );
304 protected void Act新規作成する()
306 if( DialogResult.Cancel == this.未保存なら保存する() )
307 return; // 保存がキャンセルされた場合はここで中断。
311 protected void Act開く()
313 if( DialogResult.Cancel == this.未保存なら保存する() )
314 return; // 保存がキャンセルされた場合はここで中断。
316 #region " [ファイルを開く] ダイアログでファイルを選択する。"
318 var dialog = new OpenFileDialog() {
319 Title = Properties.Resources.MSG_ファイル選択ダイアログのタイトル,
320 Filter = Properties.Resources.MSG_曲ファイル選択ダイアログのフィルタ,
322 InitialDirectory = this.作業フォルダパス,
324 var result = dialog.ShowDialog( this );
326 // メインフォームを再描画してダイアログを完全に消す。
330 if( DialogResult.OK != result )
335 this.ファイルを読み込む( dialog.FileName );
337 protected void Act指定されたファイルを開く( string ファイルパス )
339 if( DialogResult.Cancel == this.未保存なら保存する() )
340 return; // 保存がキャンセルされた場合はここで中断。
342 this.ファイルを読み込む( ファイルパス );
344 protected void Act上書き保存する()
346 if( string.IsNullOrEmpty( this.編集中のファイル名 ) )
348 #region " ファイル名が未設定なら、初めての保存と見なし、ファイル保存ダイアログで保存ファイル名を指定させる。"
350 string 絶対パスファイル名 = this.ファイル保存ダイアログを開いてファイル名を取得する();
352 if( string.IsNullOrEmpty( 絶対パスファイル名 ) )
353 return; // ファイル保存ダイアログがキャンセルされたのならここで打ち切り。
355 this.作業フォルダパス = Path.GetDirectoryName( 絶対パスファイル名 ); // ダイアログでディレクトリを変更した場合、カレントディレクトリも変更されている。
356 this.編集中のファイル名 = Path.GetFileName( 絶対パスファイル名 );
362 Path.Combine( this.作業フォルダパス, this.編集中のファイル名 ),
365 protected void Act上書き保存する( string ファイルの絶対パス, bool 一時ファイルである )
367 #region " [保存中です] ポップアップを表示する。"
369 var msg = new Popupメッセージ(
370 Properties.Resources.MSG_保存中です + Environment.NewLine +
371 Properties.Resources.MSG_しばらくお待ち下さい );
380 #region " 選択モードだったら、全チップの選択を解除する。"
383 this.選択モード.全チップの選択を解除する();
386 #region " 出力するパス内の背景動画を検索する。"
388 this.textBox背景動画.Text =
389 ( from ファイル名 in Directory.GetFiles( Path.GetDirectoryName( ファイルの絶対パス ) )
390 where SSTFormat.スコア.背景動画のデフォルト拡張子s.Any( 拡張子名 => ( Path.GetExtension( ファイル名 ).ToLower() == 拡張子名 ) )
391 select ファイル名 ).FirstOrDefault(); // 複数あったら、最初に見つけたほうを採用。1つも見つからなければ null。
394 #region " SSTFファイルを出力する。"
396 this.譜面.SSTFファイルを書き出す(
398 $"# Created by SSTFEditor {this.メジャーバージョン番号}.{this.マイナーバージョン番号}.{this.リビジョン番号}.{this.ビルド番号}" );
401 #region " 出力したファイルのパスを、[ファイル]メニューの最近使ったファイル一覧に追加する。"
403 if( false == 一時ファイルである )
405 this.Config.ファイルを最近使ったファイルの一覧に追加する( ファイルの絶対パス );
406 this.ConfigのRecentUsedFilesをファイルメニューへ追加する();
413 #region " [保存中です] ポップアップを閉じる。"
419 // 最後に、ダイアログのゴミなどを消すために再描画。
422 if( false == 一時ファイルである )
426 protected void Act名前を付けて保存する()
428 #region " ユーザに保存ファイル名を入力させる。"
430 string 絶対パスファイル名 = this.ファイル保存ダイアログを開いてファイル名を取得する();
431 if( string.IsNullOrEmpty( 絶対パスファイル名 ) )
432 return; // キャンセルされたらここで中断。
434 this.作業フォルダパス = Path.GetDirectoryName( 絶対パスファイル名 );
435 this.編集中のファイル名 = Path.GetFileName( 絶対パスファイル名 );
441 this.未保存である = true; // ウィンドウタイトルに表示されているファイル名を変更するため、一度わざと true にする。
444 protected void Act終了する()
448 protected void Act元に戻す()
450 // Undo する対象を UndoRedoリストから取得する。
451 var cell = this.UndoRedo管理.Undoするセルを取得して返す();
459 this.UndoRedo用GUIのEnabledを設定する();
460 this.選択チップの有無に応じて編集用GUIのEnabledを設定する();
463 protected void Actやり直す()
465 // Redo する対象を UndoRedoリストから取得する。
466 var cell = this.UndoRedo管理.Redoするセルを取得して返す();
474 this.UndoRedo用GUIのEnabledを設定する();
475 this.選択チップの有無に応じて編集用GUIのEnabledを設定する();
478 protected void Act切り取る()
480 // 譜面にフォーカスがないなら、何もしない。
481 if( false == this.pictureBox譜面パネル.Focused )
488 protected void Actコピーする()
490 // 譜面にフォーカスがないなら何もしない。
491 if( false == this.pictureBox譜面パネル.Focused )
495 this.クリップボード.現在選択されているチップをボードにコピーする();
498 this.選択チップの有無に応じて編集用GUIのEnabledを設定する();
501 protected void Act貼り付ける( int 貼り付けを開始する譜面内絶対位置grid )
503 // 譜面にフォーカスがないなら何もしない。
504 if( false == this.pictureBox譜面パネル.Focused )
507 this.クリップボード.チップを指定位置から貼り付ける( 貼り付けを開始する譜面内絶対位置grid );
509 protected void Act削除する()
511 // 譜面にフォーカスがないなら何もしない。
512 if( false == this.pictureBox譜面パネル.Focused )
517 this.UndoRedo管理.トランザクション記録を開始する();
519 // 譜面が持つすべてのチップについて、選択されているチップがあれば削除する。
520 for( int i = this.譜面.SSTFormatScore.チップリスト.Count - 1; 0 <= i; i-- )
522 var chip = this.譜面.SSTFormatScore.チップリスト[ i ];
526 var chip変更前 = new SSTFormat.チップ( chip );
528 var cell = new UndoRedo.セル<SSTFormat.チップ>(
530 Undoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
531 変更対象.CopyFrom( 変更前 );
532 this.譜面.SSTFormatScore.チップリスト.Add( 変更対象 );
533 this.譜面.SSTFormatScore.チップリスト.Sort();
535 Redoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
536 this.譜面.SSTFormatScore.チップリスト.Remove( 変更対象 );
545 this.UndoRedo管理.セルを追加する( cell );
552 this.UndoRedo管理.トランザクション記録を終了する();
555 this.UndoRedo用GUIのEnabledを設定する();
556 this.選択チップの有無に応じて編集用GUIのEnabledを設定する();
560 protected void Actすべて選択する()
562 // 編集モードなら強制的に選択モードにする。
564 this.選択モードに切替えて関連GUIを設定する();
566 this.選択モード.全チップを選択する();
568 protected void Act選択モードにする()
570 this.選択モードに切替えて関連GUIを設定する();
572 protected void Act編集モードにする()
574 this.編集モードに切替えて関連GUIを設定する();
576 protected void Actモードを切替える()
580 this.編集モードに切替えて関連GUIを設定する();
584 this.選択モードに切替えて関連GUIを設定する();
587 protected void Act検索する()
589 this.選択モード.検索する(); // 現在のモードに関わらず、検索はすべて選択モードオブジェクトが行う。
591 protected void Actガイド間隔を変更する( int n分 )
595 if( !( new[] { 4, 6, 8, 12, 16, 24, 32, 48, 64, 128, 0 }.Contains( n分 ) ) )
596 throw new ArgumentException( $"不正なガイド間隔({n分})が指定されました。" );
599 #region " 新しいガイド間隔を設定する。"
602 this.譜面.現在のガイド間隔を変更する( n分 ); // 譜面オブジェクトとも共有。
605 #region " ガイド間隔関連GUI(メニュー、コンボボックス)を更新する。"
607 // 一度すべてのガイド間隔メニューのチェックをはずし、制定された分数のメニューだけをチェックする。
609 this.toolStripMenuItemガイド間隔4分.CheckState = CheckState.Unchecked;
610 this.toolStripMenuItemガイド間隔6分.CheckState = CheckState.Unchecked;
611 this.toolStripMenuItemガイド間隔8分.CheckState = CheckState.Unchecked;
612 this.toolStripMenuItemガイド間隔12分.CheckState = CheckState.Unchecked;
613 this.toolStripMenuItemガイド間隔16分.CheckState = CheckState.Unchecked;
614 this.toolStripMenuItemガイド間隔24分.CheckState = CheckState.Unchecked;
615 this.toolStripMenuItemガイド間隔32分.CheckState = CheckState.Unchecked;
616 this.toolStripMenuItemガイド間隔48分.CheckState = CheckState.Unchecked;
617 this.toolStripMenuItemガイド間隔64分.CheckState = CheckState.Unchecked;
618 this.toolStripMenuItemガイド間隔128分.CheckState = CheckState.Unchecked;
619 this.toolStripMenuItemガイド間隔フリー.CheckState = CheckState.Unchecked;
623 // Menu と ComboBox の2つを変更することでイベントが2つ発生し、最終的に
624 // Actガイド間隔を変更する() を立て続けに2回呼び出してしまうことになるが……、まぁよしとする。
627 this.toolStripMenuItemガイド間隔4分.CheckState = CheckState.Checked;
628 this.toolStripComboBoxガイド間隔.SelectedIndex = 0;
632 this.toolStripMenuItemガイド間隔6分.CheckState = CheckState.Checked;
633 this.toolStripComboBoxガイド間隔.SelectedIndex = 1;
637 this.toolStripMenuItemガイド間隔8分.CheckState = CheckState.Checked;
638 this.toolStripComboBoxガイド間隔.SelectedIndex = 2;
642 this.toolStripMenuItemガイド間隔12分.CheckState = CheckState.Checked;
643 this.toolStripComboBoxガイド間隔.SelectedIndex = 3;
647 this.toolStripMenuItemガイド間隔16分.CheckState = CheckState.Checked;
648 this.toolStripComboBoxガイド間隔.SelectedIndex = 4;
652 this.toolStripMenuItemガイド間隔24分.CheckState = CheckState.Checked;
653 this.toolStripComboBoxガイド間隔.SelectedIndex = 5;
657 this.toolStripMenuItemガイド間隔32分.CheckState = CheckState.Checked;
658 this.toolStripComboBoxガイド間隔.SelectedIndex = 6;
662 this.toolStripMenuItemガイド間隔48分.CheckState = CheckState.Checked;
663 this.toolStripComboBoxガイド間隔.SelectedIndex = 7;
667 this.toolStripMenuItemガイド間隔64分.CheckState = CheckState.Checked;
668 this.toolStripComboBoxガイド間隔.SelectedIndex = 8;
672 this.toolStripMenuItemガイド間隔128分.CheckState = CheckState.Checked;
673 this.toolStripComboBoxガイド間隔.SelectedIndex = 9;
677 this.toolStripMenuItemガイド間隔フリー.CheckState = CheckState.Checked;
678 this.toolStripComboBoxガイド間隔.SelectedIndex = 10;
685 this.pictureBox譜面パネル.Invalidate();
689 protected void Actガイド間隔を拡大する()
691 switch( this.現在のガイド間隔 )
694 case 6: this.Actガイド間隔を変更する( 4 ); break;
695 case 8: this.Actガイド間隔を変更する( 6 ); break;
696 case 12: this.Actガイド間隔を変更する( 8 ); break;
697 case 16: this.Actガイド間隔を変更する( 12 ); break;
698 case 24: this.Actガイド間隔を変更する( 16 ); break;
699 case 32: this.Actガイド間隔を変更する( 24 ); break;
700 case 48: this.Actガイド間隔を変更する( 32 ); break;
701 case 64: this.Actガイド間隔を変更する( 48 ); break;
702 case 128: this.Actガイド間隔を変更する( 64 ); break;
703 case 0: this.Actガイド間隔を変更する( 128 ); break;
706 protected void Actガイド間隔を縮小する()
708 switch( this.現在のガイド間隔 )
710 case 4: this.Actガイド間隔を変更する( 6 ); break;
711 case 6: this.Actガイド間隔を変更する( 8 ); break;
712 case 8: this.Actガイド間隔を変更する( 12 ); break;
713 case 12: this.Actガイド間隔を変更する( 16 ); break;
714 case 16: this.Actガイド間隔を変更する( 24 ); break;
715 case 24: this.Actガイド間隔を変更する( 32 ); break;
716 case 32: this.Actガイド間隔を変更する( 48 ); break;
717 case 48: this.Actガイド間隔を変更する( 64 ); break;
718 case 64: this.Actガイド間隔を変更する( 128 ); break;
719 case 128: this.Actガイド間隔を変更する( 0 ); break;
723 protected void Act譜面拡大率を変更する( int n倍 )
725 if( ( 1 > n倍 ) || ( 10 < n倍 ) )
726 throw new ArgumentException( $"不正な譜面拡大率({n倍})が指定されました。" );
728 this.toolStripComboBox譜面拡大率.SelectedIndex = ( n倍 - 1 );
731 protected void Act最初から再生する()
733 this.Act指定された小節の先頭から再生する( 小節番号: 0 );
735 protected void Act現在位置から再生する()
738 int 小節番号 = this.譜面.譜面内絶対位置gridにおける小節の番号と小節先頭の位置gridを返す( this.譜面.現在のカレントラインの譜面内絶対位置grid, out 位置grid );
739 this.Act指定された小節の先頭から再生する( 小節番号 );
741 protected void Act現在位置からBGMのみ再生する()
744 int 小節番号 = this.譜面.譜面内絶対位置gridにおける小節の番号と小節先頭の位置gridを返す( this.譜面.現在のカレントラインの譜面内絶対位置grid, out 位置grid );
745 this.Act指定された小節の先頭から再生する( 小節番号, 仮想ドラムを使う: false );
747 protected void Act指定された小節の先頭から再生する( int 小節番号, bool 仮想ドラムを使う = true )
749 if( this.Config.ViewerPath.Nullまたは空である() ||
750 ( false == File.Exists( this.Config.ViewerPath ) ) )
753 // 前回のテンポラリファイルが存在していれば削除する。
754 if( File.Exists( this.最後にプレイヤーに渡した一時ファイル名 ) )
755 File.Delete( this.最後にプレイヤーに渡した一時ファイル名 );
757 // 譜面を新しくテンポラリファイルとして出力する。
760 this.最後にプレイヤーに渡した一時ファイル名 = Path.Combine( this.作業フォルダパス, Path.GetRandomFileName() );
761 } while( File.Exists( this.最後にプレイヤーに渡した一時ファイル名 ) ); // 同一名のファイルが存在してたらもう一度。(まずないだろうが)
764 this.最後にプレイヤーに渡した一時ファイル名,
765 一時ファイルである: true ); // 一時ファイルなので、「最近使ったファイル一覧」には残さない。
768 string 仮想ドラムオプション = ( 仮想ドラムを使う ) ? @" -h" : @"";
770 this.Config.ViewerPath,
771 $"\"{this.最後にプレイヤーに渡した一時ファイル名}\" -p {小節番号.ToString()}{仮想ドラムオプション}" );
773 protected void Act再生を停止する()
775 if( this.Config.ViewerPath.Nullまたは空である() ||
776 ( false == File.Exists( this.Config.ViewerPath ) ) )
779 // プレイヤーを、演奏停止オプションをつけて起動する。
780 Process.Start( this.Config.ViewerPath, @"-s" );
782 protected void Actオプションを設定する()
784 using( var dialog = new オプションダイアログ() )
786 // Config の現在の値をダイアログへ反映する。
787 dialog.checkBoxオートフォーカス.CheckState = ( this.Config.AutoFocus ) ? CheckState.Checked : CheckState.Unchecked;
788 dialog.checkBox最近使用したファイル.CheckState = ( this.Config.ShowRecentUsedFiles ) ? CheckState.Checked : CheckState.Unchecked;
789 dialog.numericUpDown最近使用したファイルの最大表示個数.Value = this.Config.MaxOfUsedRecentFiles;
790 dialog.textBoxViewerPath.Text = this.Config.ViewerPath;
792 if( DialogResult.OK == dialog.ShowDialog( this ) )
794 // 決定された値をダイアログから Config に反映する。
795 this.Config.AutoFocus = dialog.checkBoxオートフォーカス.Checked;
796 this.Config.ShowRecentUsedFiles = dialog.checkBox最近使用したファイル.Checked;
797 this.Config.MaxOfUsedRecentFiles = (int) dialog.numericUpDown最近使用したファイルの最大表示個数.Value;
798 this.Config.ViewerPath = dialog.textBoxViewerPath.Text;
801 this.ConfigのRecentUsedFilesをファイルメニューへ追加する();
804 this.Config.保存する( Path.Combine( this.ユーザフォルダパス, Properties.Resources.CONFIG_FILE_NAME ) );
808 // 画面を再描画してダイアログのゴミを消す。
811 protected void Actバージョンを表示する()
813 using( var dialog = new バージョン表示ダイアログ() )
814 dialog.ShowDialog( this );
816 protected void Act小節長倍率を変更する( int 小節番号 )
822 #region " 変更後の小節長倍率をユーザに入力させる。"
824 var db現在の小節長倍率 = this.譜面.SSTFormatScore.小節長倍率を取得する( 小節番号 );
825 using( var dialog = new 小節長倍率入力ダイアログ( 小節番号 ) )
827 dialog.倍率 = (float) db現在の小節長倍率;
828 dialog.後続も全部変更する = false;
830 if( DialogResult.OK != dialog.ShowDialog( this ) ) // キャンセルされたらここで中断。
833 変更後倍率 = (double) dialog.倍率;
834 変更終了小節番号 = ( dialog.後続も全部変更する ) ? this.譜面.SSTFormatScore.最大小節番号 : 小節番号;
842 this.UndoRedo管理.トランザクション記録を開始する();
844 for( int i = 変更開始小節番号; i <= 変更終了小節番号; i++ )
846 var 変更前倍率 = this.譜面.SSTFormatScore.小節長倍率を取得する( i );
848 #region " 新しい小節長倍率を設定する。"
850 var cell = new UndoRedo.セル<double>(
852 Undoアクション: ( 変更対象, 変更前, 変更後, 対象小節番号, 任意2 ) => {
853 this.譜面.SSTFormatScore.小節長倍率を設定する( (int) 対象小節番号, 変更前 );
856 Redoアクション: ( 変更対象, 変更前, 変更後, 対象小節番号, 任意2 ) => {
857 this.譜面.SSTFormatScore.小節長倍率を設定する( (int) 対象小節番号, 変更後 );
866 this.UndoRedo管理.セルを追加する( cell );
870 #region " チップを移動または削除する。"
872 int 変化量grid = (int) ( ( 変更後倍率 - 変更前倍率 ) * this.GRID_PER_PART );
874 for( int j = this.譜面.SSTFormatScore.チップリスト.Count - 1; j >= 0; j-- ) // 削除する場合があるので後ろからカウントする。
876 var chip = this.譜面.SSTFormatScore.チップリスト[ j ];
878 // (A) 変更対象の小節内のチップ → 移動なし。カウント変更あり。小節はみ出しチェックあり。
881 #region " 小節からはみ出したチップは、削除する。"
883 int 次小節の先頭位置grid = this.譜面.小節先頭の譜面内絶対位置gridを返す( i ) + (int) ( 変更後倍率 * this.GRID_PER_PART );
884 if( 次小節の先頭位置grid <= chip.譜面内絶対位置grid )
886 var chip変更前 = new SSTFormat.チップ( chip );
888 var cc = new UndoRedo.セル<SSTFormat.チップ>(
890 Undoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
891 変更対象.CopyFrom( 変更前 );
892 this.譜面.SSTFormatScore.チップリスト.Add( 変更対象 );
893 this.譜面.SSTFormatScore.チップリスト.Sort();
896 Redoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
897 this.譜面.SSTFormatScore.チップリスト.Remove( 変更対象 );
906 this.UndoRedo管理.セルを追加する( cc );
911 #region " 小節からはみ出さなかったチップは、カウント(小節解像度と小節内位置)を変更する。"
915 // 解像度が小さいと計算結果がおかしくなるので、無条件に解像度を上げる。
917 int 十分に大きな値 = this.GRID_PER_PART; // 充分に大きい数なら何でもいい。
918 if( 十分に大きな値 > chip.小節解像度 ) // 何度も乗算されたら値が肥大化しまくるので、制限をかける。
920 chip.小節解像度 *= 十分に大きな値;
921 chip.小節内位置 *= 十分に大きな値;
924 // 小節解像度を変更する。(小節内位置は変更しない。)
925 chip.小節解像度 = (int) ( 変更後倍率 * chip.小節解像度 );
931 // (B) 変更対象より先の小節内のチップ → 移動あり。カウントなし。小節はみ出しチェックなし。
932 else if( i < chip.小節番号 )
934 #region " チップを n変化量grid 移動する。"
936 var cc = new UndoRedo.セル<SSTFormat.チップ>(
938 Undoアクション: ( 変更対象, 変更前, 変更後, _変化量grid, 任意2 ) => {
939 変更対象.譜面内絶対位置grid -= (int) _変化量grid;
942 Redoアクション: ( 変更対象, 変更前, 変更後, _変化量grid, 任意2 ) => {
943 変更対象.譜面内絶対位置grid += (int) _変化量grid;
952 this.UndoRedo管理.セルを追加する( cc );
964 this.UndoRedo管理.トランザクション記録を終了する();
967 this.UndoRedo用GUIのEnabledを設定する();
971 protected void Act小節を挿入する( int 挿入前小節番号 )
973 // 挿入する新しい小節の小節長は、直前の(挿入前小節番号-1 の小節)と同じサイズとする。
974 double 小節長倍率 = ( 0 < 挿入前小節番号 ) ? this.譜面.SSTFormatScore.小節長倍率を取得する( 挿入前小節番号 - 1 ) : 1.0;
979 this.UndoRedo管理.トランザクション記録を開始する();
981 #region " 後方のチップを移動する。"
983 int 挿入に伴う増加量grid = (int) ( this.GRID_PER_PART * 小節長倍率 );
985 foreach( var chip in this.譜面.SSTFormatScore.チップリスト )
987 if( 挿入前小節番号 <= chip.小節番号 )
989 var cell = new UndoRedo.セル<SSTFormat.チップ>(
991 Undoアクション: ( 変更対象, 変更前, 変更後, _挿入に伴う増加量grid, 任意2 ) => {
993 変更対象.譜面内絶対位置grid -= (int) _挿入に伴う増加量grid;
995 Redoアクション: ( 変更対象, 変更前, 変更後, _挿入に伴う増加量grid, 任意2 ) => {
997 変更対象.譜面内絶対位置grid += (int) _挿入に伴う増加量grid;
1005 this.UndoRedo管理.セルを追加する( cell );
1011 #region " 後方の小節長倍率を移動する。"
1013 var cc = new UndoRedo.セル<double>(
1015 Undoアクション: ( 変更対象, 変更前, 変更後, _挿入前小節番号, 任意2 ) => {
1016 this.譜面.SSTFormatScore.小節長倍率リスト.RemoveAt( (int) _挿入前小節番号 );
1019 Redoアクション: ( 変更対象, 変更前, 変更後, _挿入前小節番号, 任意2 ) => {
1020 this.譜面.SSTFormatScore.小節長倍率リスト.Insert( (int) _挿入前小節番号, 小節長倍率 );
1029 this.UndoRedo管理.セルを追加する( cc );
1036 this.UndoRedo管理.トランザクション記録を終了する();
1039 this.UndoRedo用GUIのEnabledを設定する();
1044 protected void Act小節を削除する( int 削除する小節番号 )
1046 double 削除する小節の小節長倍率 = this.譜面.SSTFormatScore.小節長倍率を取得する( 削除する小節番号 );
1051 this.UndoRedo管理.トランザクション記録を開始する();
1053 #region " 削除される小節内のチップをすべて削除する。"
1055 for( int i = this.譜面.SSTFormatScore.チップリスト.Count - 1; i >= 0; i-- )
1057 var chip = this.譜面.SSTFormatScore.チップリスト[ i ];
1059 if( 削除する小節番号 == chip.小節番号 )
1061 var chip変更前 = new SSTFormat.チップ( chip );
1063 var cell = new UndoRedo.セル<SSTFormat.チップ>(
1065 Undoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
1066 変更対象.CopyFrom( 変更前 );
1067 this.譜面.SSTFormatScore.チップリスト.Add( 変更対象 );
1068 this.譜面.SSTFormatScore.チップリスト.Sort();
1070 Redoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
1071 this.譜面.SSTFormatScore.チップリスト.Remove( 変更対象 );
1080 this.UndoRedo管理.セルを追加する( cell );
1086 #region " 後方のチップを移動する。"
1088 int 削除に伴う減少量grid = (int) ( this.GRID_PER_PART * 削除する小節の小節長倍率 );
1090 foreach( var chip in this.譜面.SSTFormatScore.チップリスト )
1092 if( 削除する小節番号 < chip.小節番号 )
1094 var cell = new UndoRedo.セル<SSTFormat.チップ>(
1096 Undoアクション: ( 変更対象, 変更前, 変更後, _削除に伴う減少量grid, 任意2 ) => {
1098 変更対象.譜面内絶対位置grid += (int) _削除に伴う減少量grid;
1100 Redoアクション: ( 変更対象, 変更前, 変更後, _削除に伴う減少量grid, 任意2 ) => {
1102 変更対象.譜面内絶対位置grid -= (int) _削除に伴う減少量grid;
1110 this.UndoRedo管理.セルを追加する( cell );
1116 #region " 後方の小節長倍率を移動する。"
1118 var cc = new UndoRedo.セル<double>(
1120 Undoアクション: ( 変更対象, 変更前, 変更後, _削除する小節番号, 任意2 ) => {
1121 this.譜面.SSTFormatScore.小節長倍率リスト.Insert( (int) _削除する小節番号, 変更前 );
1124 Redoアクション: ( 変更対象, 変更前, 変更後, _削除する小節番号, 任意2 ) => {
1125 this.譜面.SSTFormatScore.小節長倍率リスト.RemoveAt( (int) _削除する小節番号 );
1129 変更前の値: 削除する小節の小節長倍率,
1134 this.UndoRedo管理.セルを追加する( cc );
1141 this.UndoRedo管理.トランザクション記録を終了する();
1144 this.UndoRedo用GUIのEnabledを設定する();
1148 protected void Act小節の先頭へ移動する( int 小節番号 )
1153 else if( 小節番号 > this.譜面.SSTFormatScore.最大小節番号 )
1154 小節番号 = this.譜面.SSTFormatScore.最大小節番号;
1156 // 垂直スクロールバーを移動させると、画面も自動的に移動する。
1157 var bar = this.vScrollBar譜面用垂直スクロールバー;
1158 bar.Value = ( ( bar.Maximum + 1 ) - bar.LargeChange ) - this.譜面.小節先頭の譜面内絶対位置gridを返す( 小節番号 );
1163 protected void エディタを初期化する()
1165 this.編集中のファイル名 = null;
1167 #region " 各種オブジェクトを生成する。"
1170 this.譜面 = new C譜面( this ); // 譜面は、選択・編集モードよりも先に生成すること。
1172 this.UndoRedo管理 = new UndoRedo.管理();
1173 this.選択モード = new 選択モード( this );
1174 this.編集モード = new 編集モード( this );
1175 this.クリップボード = new クリップボード( this );
1183 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
1184 this.textBox曲名.Clear();
1186 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
1187 this.textBox説明.Clear();
1190 #region " Viewer 再生 "
1192 this.Viewer再生関連GUIのEnabledを設定する();
1197 this.Actガイド間隔を変更する( 16 ); // 初期値は 1/16。
1202 this.Act譜面拡大率を変更する( 1 ); // 初期値は x1.0。
1205 #region " Undo/Redo "
1207 this.次のプロパティ変更がUndoRedoリストに載るようにする();
1208 this.UndoRedo用GUIのEnabledを設定する();
1211 #region " 垂直スクロールバー "
1213 this.vScrollBar譜面用垂直スクロールバー.Minimum = 0;
1214 this.vScrollBar譜面用垂直スクロールバー.Maximum = ( this.譜面.全小節の高さgrid - 1 );
1215 this.vScrollBar譜面用垂直スクロールバー.SmallChange = ( this.GRID_PER_PART / 16 );
1216 this.vScrollBar譜面用垂直スクロールバー.LargeChange = this.GRID_PER_PART;
1217 this.vScrollBar譜面用垂直スクロールバー.Value = this.vScrollBar譜面用垂直スクロールバー.Maximum - this.vScrollBar譜面用垂直スクロールバー.LargeChange;
1223 this.編集モードに切替えて関連GUIを設定する();
1224 this.未保存である = false;
1226 protected DialogResult 未保存なら保存する()
1228 #region " 既に保存済みなら何もしない。"
1230 if( false == this.未保存である )
1231 return DialogResult.OK;
1234 #region "[編集中のデータを保存しますか?] ダイアログを表示し、回答を待つ。"
1236 var result = MessageBox.Show(
1237 Properties.Resources.MSG_編集中のデータを保存しますか,
1238 Properties.Resources.MSG_確認ダイアログのタイトル,
1239 MessageBoxButtons.YesNoCancel,
1240 MessageBoxIcon.Question,
1241 MessageBoxDefaultButton.Button1 );
1244 #region " YES なら上書き保存する。"
1246 if( DialogResult.Yes == result )
1250 #region " 画面を再描画してダイアログを消去する。"
1256 return result; // ダイアログの結果を返す。
1258 protected string ファイル保存ダイアログを開いてファイル名を取得する()
1260 DialogResult result;
1263 // ダイアログでファイル名を取得する。
1264 using( var dialog = new SaveFileDialog() {
1266 Filter = "SSTFファイル(*.sstf)|*.sstf",
1268 InitialDirectory = this.作業フォルダパス,
1271 result = dialog.ShowDialog( this );
1272 ファイル名 = dialog.FileName;
1275 // 画面を再描画してダイアログのゴミを消去する。
1278 // キャンセルされたら ""(空文字列)を返す。
1279 if( DialogResult.OK != result )
1282 // ファイルの拡張子を .sstf に変更。
1283 if( 0 == Path.GetExtension( ファイル名 ).Length )
1284 ファイル名 = Path.ChangeExtension( ファイル名, ".sstf" );
1288 protected void ファイルを読み込む( string ファイル名 )
1292 #region " [読み込み中です] ポップアップを表示する。"
1294 var msg = new Popupメッセージ(
1295 Properties.Resources.MSG_読み込み中です + Environment.NewLine +
1296 Properties.Resources.MSG_しばらくお待ち下さい );
1305 this.譜面.曲データファイルを読み込む( ファイル名 );
1307 // 最低でも 10 小節は存在させる。
1308 for( int n = this.譜面.SSTFormatScore.最大小節番号 + 1; n < 9; n++ )
1311 string 読み込み時の拡張子 = Path.GetExtension( ファイル名 ).ToLower();
1312 this.編集中のファイル名 = Path.ChangeExtension( Path.GetFileName( ファイル名 ), ".sstf" ); // 読み込んだファイルの拡張子を .sstf に変換。
1313 this.作業フォルダパス = Path.GetDirectoryName( ファイル名 );
1315 // 読み込んだファイルを [ファイル]メニューの最近使ったファイル一覧に追加する。
1316 this.Config.ファイルを最近使ったファイルの一覧に追加する( Path.Combine( this.作業フォルダパス, this.編集中のファイル名 ) );
1317 this.ConfigのRecentUsedFilesをファイルメニューへ追加する();
1320 譜面.SSTFormatScore.背景動画ファイル名 =
1321 ( from file in Directory.GetFiles( Path.GetDirectoryName( this.作業フォルダパス ) )
1322 where SSTFormat.スコア.背景動画のデフォルト拡張子s.Any( 拡張子名 => ( Path.GetExtension( file ).ToLower() == 拡張子名 ) )
1323 select file ).FirstOrDefault(); // 複数あったら、最初に見つけたほうを採用。1つも見つからなければ null。
1324 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
1325 this.textBox曲名.Text = 譜面.SSTFormatScore.Header.曲名;
1326 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
1327 this.textBox説明.Text = 譜面.SSTFormatScore.Header.説明文;
1328 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
1329 this.textBox背景動画.Text = Path.GetFileName( 譜面.SSTFormatScore.背景動画ファイル名 );
1330 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
1331 this.textBoxメモ.Text = ( this.譜面.SSTFormatScore.dicメモ.ContainsKey( 0 ) ) ? this.譜面.SSTFormatScore.dicメモ[ 0 ] : "";
1333 // ウィンドウのタイトルバーの表示変更(str編集中のファイル名 が確定した後に)
1334 this.未保存である = true; // 以前の状態によらず、確実に更新するようにする。
1336 // sstf 以外を読み込んだ場合は、未保存状態のままとする。
1337 if( 読み込み時の拡張子.ToLower() == ".sstf" )
1338 this.未保存である = false;
1340 catch( InvalidDataException )
1343 Properties.Resources.MSG_対応していないファイルです,
1344 Properties.Resources.MSG_確認ダイアログのタイトル,
1345 MessageBoxButtons.OK );
1348 #region "「読み込み中です」ポップアップを閉じる。 "
1354 // 最後に、ダイアログのゴミなどを消すために画面を再描画する。
1357 protected enum タブ種別 : int { 基本情報 = 0 }
1358 protected void タブを選択する( タブ種別 eタブ種別 )
1360 this.tabControl情報タブコンテナ.SelectedIndex = (int) eタブ種別;
1362 protected void 次のプロパティ変更がUndoRedoリストに載らないようにする()
1364 UndoRedo.管理.UndoRedoした直後である = true;
1366 protected void 次のプロパティ変更がUndoRedoリストに載るようにする()
1368 UndoRedo.管理.UndoRedoした直後である = false;
1370 protected void 垂直スクロールバーと譜面の上下位置を調整する()
1372 var bar = this.vScrollBar譜面用垂直スクロールバー;
1373 var box = this.pictureBox譜面パネル;
1374 var panel2 = this.splitContainer分割パネルコンテナ.Panel2;
1376 // 譜面パネルの長さをパネルに合わせて調整する。
1377 box.ClientSize = new Size(
1378 box.ClientSize.Width,
1379 panel2.ClientSize.Height - box.Location.Y );
1381 // 現在のバーの位置を割合で記憶する。
1382 var bar率 = (double) bar.Value / (double) ( bar.Maximum - bar.Minimum );
1384 // 新しい値域を設定した後、バーの位置を記憶しておいた割合で設定。
1386 bar.Maximum = this.譜面.全小節の高さgrid - 1;
1387 bar.Value = (int) ( ( bar.Maximum - bar.Minimum ) * bar率 );
1389 // 譜面長さが画面長さより短いなら、スクロールバーを表示しない。
1390 bar.Enabled = ( bar.Maximum > bar.LargeChange ) ? true : false;
1392 protected void Viewer再生関連GUIのEnabledを設定する()
1394 if( File.Exists( this.Config.ViewerPath ) )
1396 // (A) Viewer が存在するなら、各GUIは有効。
1398 this.toolStripButton先頭から再生.Enabled = true;
1399 this.toolStripButton現在位置から再生.Enabled = true;
1400 this.toolStripButton現在位置からBGMのみ再生.Enabled = true;
1401 this.toolStripButton再生停止.Enabled = true;
1403 this.toolStripMenuItem先頭から再生.Enabled = true;
1404 this.toolStripMenuItem現在位置から再生.Enabled = true;
1405 this.toolStripMenuItem現在位置からBGMのみ再生.Enabled = true;
1406 this.toolStripMenuItem再生停止.Enabled = true;
1410 // (B) Viewer が存在しないなら、各GUIは無効。
1412 this.toolStripButton先頭から再生.Enabled = false;
1413 this.toolStripButton現在位置から再生.Enabled = false;
1414 this.toolStripButton現在位置からBGMのみ再生.Enabled = false;
1415 this.toolStripButton再生停止.Enabled = false;
1417 this.toolStripMenuItem先頭から再生.Enabled = false;
1418 this.toolStripMenuItem現在位置から再生.Enabled = false;
1419 this.toolStripMenuItem現在位置からBGMのみ再生.Enabled = false;
1420 this.toolStripMenuItem再生停止.Enabled = false;
1423 protected void ConfigのRecentUsedFilesをファイルメニューへ追加する()
1425 #region " [ファイル] メニューから、[最近使ったファイルの一覧] をクリアする。"
1427 for( int i = 0; i < this.toolStripMenuItemファイル.DropDownItems.Count; i++ )
1429 var item = this.toolStripMenuItemファイル.DropDownItems[ i ];
1431 // ↓削除したくないサブメニューの一覧。これ以外のサブメニュー項目はすべて削除する。
1432 if( item != this.toolStripMenuItem新規作成 &&
1433 item != this.toolStripMenuItem開く &&
1434 item != this.toolStripMenuItem上書き保存 &&
1435 item != this.toolStripMenuItem名前を付けて保存 &&
1436 item != this.toolStripSeparator1 &&
1437 item != this.toolStripMenuItem終了 )
1439 this.toolStripMenuItemファイル.DropDownItems.Remove( item );
1440 i = -1; // 要素数が変わったので列挙しなおし。RemoveAll() はないのか。
1446 if( ( false == this.Config.ShowRecentUsedFiles ) || // 表示しない or
1447 ( 0 == this.Config.RecentUsedFiles.Count ) ) // 履歴が 0 件
1450 #region " Config が持つ履歴にそって、[ファイル] メニューにサブメニュー項目リストを追加する(ただし最大表示数まで)。"
1452 // [File] のサブメニューリストに項目が1つでもある場合は、履歴サブメニュー項目を追加する前に、[終了] の下にセパレータを入れる。手動で。
1453 bool セパレータの追加がまだ = true;
1455 // すべての [最近使ったファイル] について...
1456 for( int i = 0; i < this.Config.RecentUsedFiles.Count; i++ )
1459 if( this.Config.MaxOfUsedRecentFiles <= i )
1462 // ファイルパスを、サブメニュー項目として [ファイル] メニューに追加する。
1463 string ファイルパス = this.Config.RecentUsedFiles[ i ];
1464 if( string.IsNullOrEmpty( ファイルパス ) )
1467 // セパレータの追加がまだなら追加する。
1470 this.toolStripMenuItemファイル.DropDownItems.Add( new ToolStripSeparator() { Size = this.toolStripSeparator1.Size } );
1471 セパレータの追加がまだ = false;
1474 // ToolStripMenuItem を手動で作って [ファイル] のサブメニューリストに追加する。
1475 var item = new ToolStripMenuItem() {
1476 Name = "最近使ったファイル" + i,
1477 Size = this.toolStripMenuItem終了.Size,
1478 Text = "&" + i + " " + ファイルパス,
1480 item.Click += new EventHandler( this.toolStripMenuItem最近使ったファイル_Click );
1481 this.toolStripMenuItemファイル.DropDownItems.Add( item );
1483 // 追加したファイルが既に存在していないなら項目を無効化(グレー表示)する。
1484 if( false == File.Exists( ファイルパス ) )
1485 item.Enabled = false;
1490 protected Point 現在のマウス位置を譜面パネル内座標pxに変換して返す()
1492 return this.pictureBox譜面パネル.PointToClient( new Point( Cursor.Position.X, Cursor.Position.Y ) );
1494 protected void 現在のチップ音量をツールバーに表示する()
1496 this.toolStripLabel音量.Text = ( this.dic音量ラベル.ContainsKey( this.現在のチップ音量 ) ) ? this.dic音量ラベル[ this.現在のチップ音量 ] : @"???";
1503 protected void メインフォーム_DragDrop( object sender, DragEventArgs e )
1505 string[] data = (string[]) e.Data.GetData( DataFormats.FileDrop );
1507 if( 1 <= data.Length )
1508 this.Act指定されたファイルを開く( data[ 0 ] ); // Dropされたファイルが複数個あっても、先頭のファイルだけを有効とする。
1510 protected void メインフォーム_DragEnter( object sender, DragEventArgs e )
1512 if( e.Data.GetDataPresent( DataFormats.FileDrop ) )
1514 e.Effect = DragDropEffects.Copy; // ファイルならコピーと見なす(カーソルがコピー型になる)
1518 e.Effect = DragDropEffects.None; // ファイルじゃないなら無視(カーソル変化なし)
1521 protected void メインフォーム_FormClosing( object sender, FormClosingEventArgs e )
1523 if( DialogResult.Cancel == this.未保存なら保存する() )
1537 protected void toolStripMenuItem新規作成_Click( object sender, EventArgs e )
1541 protected void toolStripMenuItem開く_Click( object sender, EventArgs e )
1545 protected void toolStripMenuItem上書き保存_Click( object sender, EventArgs e )
1549 protected void toolStripMenuItem名前を付けて保存_Click( object sender, EventArgs e )
1551 this.Act名前を付けて保存する();
1553 protected void toolStripMenuItem終了_Click( object sender, EventArgs e )
1557 protected void toolStripMenuItem最近使ったファイル_Click( object sender, EventArgs e )
1559 // ※このイベントハンドラに対応する「toolStripMenuItem最近使ったファイル」というアイテムはデザイナにはないので注意。
1560 // 「this.t最近使ったファイルをFileメニューへ追加する()」の中で、手動で作って追加したアイテムに対するハンドラである。
1562 this.Act指定されたファイルを開く( ( (ToolStripMenuItem) sender ).Text.Substring( 3 ) );
1566 protected void toolStripMenuItem元に戻す_Click( object sender, EventArgs e )
1570 protected void toolStripMenuItemやり直す_Click( object sender, EventArgs e )
1574 protected void toolStripMenuItem切り取り_Click( object sender, EventArgs e )
1578 protected void toolStripMenuItemコピー_Click( object sender, EventArgs e )
1582 protected void toolStripMenuItem貼り付け_Click( object sender, EventArgs e )
1584 var マウスの位置 = this.現在のマウス位置を譜面パネル内座標pxに変換して返す();
1586 // (A) マウスが譜面上になかった → 表示領域下辺から貼り付ける。
1587 if( ( ( 0 > マウスの位置.X ) || ( 0 > マウスの位置.Y ) ) ||
1588 ( ( マウスの位置.X > this.譜面パネルサイズ.Width ) || ( マウスの位置.Y > this.譜面パネルサイズ.Height ) ) )
1590 this.Act貼り付ける( this.譜面.現在の譜面表示下辺の譜面内絶対位置grid );
1592 // (B) マウスが譜面上にある → そこから貼り付ける。
1595 this.Act貼り付ける( this.譜面.譜面パネル内Y座標pxにおける譜面内絶対位置gridをガイド幅単位で返す( マウスの位置.Y ) );
1598 protected void toolStripMenuItem削除_Click( object sender, EventArgs e )
1602 protected void toolStripMenuItemすべて選択_Click( object sender, EventArgs e )
1606 protected void toolStripMenuItem選択モード_Click( object sender, EventArgs e )
1608 this.選択モードに切替えて関連GUIを設定する();
1610 protected void toolStripMenuItem編集モード_Click( object sender, EventArgs e )
1612 this.編集モードに切替えて関連GUIを設定する();
1614 protected void toolStripMenuItemモード切替え_Click( object sender, EventArgs e )
1618 this.編集モードに切替えて関連GUIを設定する();
1622 this.選択モードに切替えて関連GUIを設定する();
1625 protected void toolStripMenuItem検索_Click( object sender, EventArgs e )
1631 protected void toolStripMenuItemガイド間隔4分_Click( object sender, EventArgs e )
1633 this.Actガイド間隔を変更する( 4 );
1635 protected void toolStripMenuItemガイド間隔6分_Click( object sender, EventArgs e )
1637 this.Actガイド間隔を変更する( 6 );
1639 protected void toolStripMenuItemガイド間隔8分_Click( object sender, EventArgs e )
1641 this.Actガイド間隔を変更する( 8 );
1643 protected void toolStripMenuItemガイド間隔12分_Click( object sender, EventArgs e )
1645 this.Actガイド間隔を変更する( 12 );
1647 protected void toolStripMenuItemガイド間隔16分_Click( object sender, EventArgs e )
1649 this.Actガイド間隔を変更する( 16 );
1651 protected void toolStripMenuItemガイド間隔24分_Click( object sender, EventArgs e )
1653 this.Actガイド間隔を変更する( 24 );
1655 protected void toolStripMenuItemガイド間隔32分_Click( object sender, EventArgs e )
1657 this.Actガイド間隔を変更する( 32 );
1659 protected void toolStripMenuItemガイド間隔48分_Click( object sender, EventArgs e )
1661 this.Actガイド間隔を変更する( 48 );
1663 protected void toolStripMenuItemガイド間隔64分_Click( object sender, EventArgs e )
1665 this.Actガイド間隔を変更する( 64 );
1667 protected void toolStripMenuItemガイド間隔128分_Click( object sender, EventArgs e )
1669 this.Actガイド間隔を変更する( 128 );
1671 protected void toolStripMenuItemガイド間隔フリー_Click( object sender, EventArgs e )
1673 this.Actガイド間隔を変更する( 0 );
1675 protected void toolStripMenuItemガイド間隔拡大_Click( object sender, EventArgs e )
1677 this.Actガイド間隔を拡大する();
1679 protected void toolStripMenuItemガイド間隔縮小_Click( object sender, EventArgs e )
1681 this.Actガイド間隔を縮小する();
1685 protected void toolStripMenuItem先頭から再生_Click( object sender, EventArgs e )
1689 protected void toolStripMenuItem現在位置から再生_Click( object sender, EventArgs e )
1691 this.Act現在位置から再生する();
1693 protected void toolStripMenuItem現在位置からBGMのみ再生_Click( object sender, EventArgs e )
1695 this.Act現在位置からBGMのみ再生する();
1697 protected void toolStripMenuItem再生停止_Click( object sender, EventArgs e )
1703 protected void toolStripMenuItemオプション_Click( object sender, EventArgs e )
1705 this.Actオプションを設定する();
1709 protected void toolStripMenuItemバージョン_Click( object sender, EventArgs e )
1711 this.Actバージョンを表示する();
1717 protected void toolStripButton新規作成_Click( object sender, EventArgs e )
1721 protected void toolStripButton開く_Click( object sender, EventArgs e )
1725 protected void toolStripButton上書き保存_Click( object sender, EventArgs e )
1729 protected void toolStripButton切り取り_Click( object sender, EventArgs e )
1733 protected void toolStripButtonコピー_Click( object sender, EventArgs e )
1737 protected void toolStripButton貼り付け_Click( object sender, EventArgs e )
1739 var マウスの位置 = this.現在のマウス位置を譜面パネル内座標pxに変換して返す();
1741 // (A) マウスが譜面上になかった → 表示領域下辺から貼り付ける。
1742 if( ( ( マウスの位置.X < 0 ) || ( マウスの位置.Y < 0 ) ) ||
1743 ( ( マウスの位置.X > this.譜面パネルサイズ.Width ) || ( マウスの位置.Y > this.譜面パネルサイズ.Height ) ) )
1745 this.Act貼り付ける( this.譜面.現在の譜面表示下辺の譜面内絶対位置grid );
1747 // (B) マウスが譜面上にある → そこから貼り付ける。
1750 this.Act貼り付ける( this.譜面.譜面パネル内Y座標pxにおける譜面内絶対位置gridをガイド幅単位で返す( マウスの位置.Y ) );
1753 protected void toolStripButton削除_Click( object sender, EventArgs e )
1758 protected void toolStripButton元に戻す_Click( object sender, EventArgs e )
1762 protected void toolStripButtonやり直す_Click( object sender, EventArgs e )
1767 protected void toolStripComboBox譜面拡大率_SelectedIndexChanged( object sender, EventArgs e )
1769 this.Act譜面拡大率を変更する( this.toolStripComboBox譜面拡大率.SelectedIndex + 1 );
1771 protected void toolStripComboBoxガイド間隔_SelectedIndexChanged( object sender, EventArgs e )
1773 switch( this.toolStripComboBoxガイド間隔.SelectedIndex )
1776 this.Actガイド間隔を変更する( 4 );
1780 this.Actガイド間隔を変更する( 6 );
1784 this.Actガイド間隔を変更する( 8 );
1788 this.Actガイド間隔を変更する( 12 );
1792 this.Actガイド間隔を変更する( 16 );
1796 this.Actガイド間隔を変更する( 24 );
1800 this.Actガイド間隔を変更する( 32 );
1804 this.Actガイド間隔を変更する( 48 );
1808 this.Actガイド間隔を変更する( 64 );
1812 this.Actガイド間隔を変更する( 128 );
1816 this.Actガイド間隔を変更する( 0 );
1821 protected void toolStripButton選択モード_Click( object sender, EventArgs e )
1825 protected void toolStripButton編集モード_Click( object sender, EventArgs e )
1830 protected void toolStripButton先頭から再生_Click( object sender, EventArgs e )
1834 protected void toolStripButton現在位置から再生_Click( object sender, EventArgs e )
1836 this.Act現在位置から再生する();
1838 protected void toolStripButton現在位置からBGMのみ再生_Click( object sender, EventArgs e )
1840 this.Act現在位置からBGMのみ再生する();
1842 protected void toolStripButton再生停止_Click( object sender, EventArgs e )
1847 protected void toolStripButton音量Down_Click( object sender, EventArgs e )
1849 int 新音量 = this.現在のチップ音量 - 1;
1850 this.現在のチップ音量 = ( 新音量 < メインフォーム.最小音量 ) ? メインフォーム.最小音量 : 新音量;
1852 this.現在のチップ音量をツールバーに表示する();
1854 protected void toolStripButton音量UP_Click( object sender, EventArgs e )
1856 int 新音量 = this.現在のチップ音量 + 1;
1857 this.現在のチップ音量 = ( 新音量 > メインフォーム.最大音量 ) ? メインフォーム.最大音量 : 新音量;
1859 this.現在のチップ音量をツールバーに表示する();
1863 #region " 分割パネルコンテナ、譜面パネル、スクロールバー "
1865 protected void pictureBox譜面パネル_MouseClick( object sender, MouseEventArgs e )
1868 this.pictureBox譜面パネル.Focus();
1870 // 選択・編集モードオブジェクトのいずれかへ処理を引き継ぐ。
1873 this.選択モード.MouseClick( e );
1877 this.編集モード.MouseClick( e );
1880 protected void pictureBox譜面パネル_MouseDown( object sender, MouseEventArgs e )
1882 // 選択モードオブジェクトへ処理を引き継ぐ。
1884 this.選択モード.MouseDown( e );
1886 protected void pictureBox譜面パネル_MouseEnter( object sender, EventArgs e )
1888 // オートフォーカスが有効の場合、譜面にマウスが入ったら譜面がフォーカスを得る。"
1889 if( this.Config.AutoFocus )
1890 this.pictureBox譜面パネル.Focus();
1892 protected void pictureBox譜面パネル_MouseLeave( object sender, EventArgs e )
1894 // 編集モードオブジェクトへ処理を引き継ぐ。
1896 this.編集モード.MouseLeave( e );
1898 protected void pictureBox譜面パネル_MouseMove( object sender, MouseEventArgs e )
1900 // 選択・編集モードオブジェクトのいずれかへ処理を引き継ぐ。
1903 this.選択モード.MouseMove( e );
1907 this.編集モード.MouseMove( e );
1910 protected void pictureBox譜面パネル_Paint( object sender, PaintEventArgs e )
1912 if( false == this.初期化完了 )
1913 return; // 初期化が終わってないのに呼び出されることがあるので、その場合は無視。
1915 #region " 小節数が変わってたら、スクロールバーの値域を調整する。"
1917 int 全譜面の高さgrid = this.譜面.全小節の高さgrid;
1919 if( this.vScrollBar譜面用垂直スクロールバー.Maximum != 全譜面の高さgrid - 1 ) // 小節数が変わっている
1921 // 譜面の高さ(grid)がどれだけ変わったか?
1922 int 増加分grid = ( 全譜面の高さgrid - 1 ) - this.vScrollBar譜面用垂直スクロールバー.Maximum;
1924 #region " スクロールバーの状態を新しい譜面の高さに合わせる。"
1927 int value = this.vScrollBar譜面用垂直スクロールバー.Value; // 次の式で Maximum が Value より小さくなると例外が発生するので、
1928 this.vScrollBar譜面用垂直スクロールバー.Value = 0; // Value のバックアップを取っておいて、ひとまず 0 にする。
1929 this.vScrollBar譜面用垂直スクロールバー.Maximum = 全譜面の高さgrid - 1;
1931 int newValue = value + 増加分grid;
1933 // オーバーフローしないようクリッピングする。
1936 this.vScrollBar譜面用垂直スクロールバー.Value = 0;
1938 else if( ( this.vScrollBar譜面用垂直スクロールバー.Maximum - this.vScrollBar譜面用垂直スクロールバー.LargeChange ) <= newValue )
1940 this.vScrollBar譜面用垂直スクロールバー.Value = this.vScrollBar譜面用垂直スクロールバー.Maximum - this.vScrollBar譜面用垂直スクロールバー.LargeChange;
1944 this.vScrollBar譜面用垂直スクロールバー.Value = newValue;
1949 #region " 譜面表示下辺の位置を更新する。"
1951 this.譜面.現在の譜面表示下辺の譜面内絶対位置grid =
1952 ( ( this.vScrollBar譜面用垂直スクロールバー.Maximum - this.vScrollBar譜面用垂直スクロールバー.LargeChange ) + 1 ) - this.vScrollBar譜面用垂直スクロールバー.Value;
1960 this.譜面.描画する( e.Graphics, this.pictureBox譜面パネル );
1964 // 選択・編集モードオブジェクトのいずれかへ処理を引き継ぐ。
1967 this.選択モード.Paint( e );
1971 this.編集モード.Paint( e );
1974 protected void pictureBox譜面パネル_PreviewKeyDown( object sender, PreviewKeyDownEventArgs e )
1976 if( Keys.Prior == e.KeyCode )
1978 #region " PageUp → 移動量に対応する grid だけ垂直つまみを移動させる。あとはこの移動で生じる ChangedValue イベントで処理。"
1980 int 移動すべき数grid = -this.GRID_PER_PART;
1981 int 新しい位置 = this.vScrollBar譜面用垂直スクロールバー.Value + 移動すべき数grid;
1982 int 最小値 = this.vScrollBar譜面用垂直スクロールバー.Minimum;
1983 int 最大値 = ( this.vScrollBar譜面用垂直スクロールバー.Maximum + 1 ) - this.vScrollBar譜面用垂直スクロールバー.LargeChange;
1989 else if( 新しい位置 > 最大値 )
1993 this.vScrollBar譜面用垂直スクロールバー.Value = 新しい位置;
1997 else if( Keys.Next == e.KeyCode )
1999 #region " PageDown → 移動量に対応する grid だけ垂直つまみを移動させる。あとはこの移動で生じる ChangedValue イベントで処理。"
2001 int 移動すべき数grid = this.GRID_PER_PART;
2002 int 新しい位置 = this.vScrollBar譜面用垂直スクロールバー.Value + 移動すべき数grid;
2003 int 最小値 = this.vScrollBar譜面用垂直スクロールバー.Minimum;
2004 int 最大値 = ( this.vScrollBar譜面用垂直スクロールバー.Maximum + 1 ) - this.vScrollBar譜面用垂直スクロールバー.LargeChange;
2010 else if( 新しい位置 > 最大値 )
2014 this.vScrollBar譜面用垂直スクロールバー.Value = 新しい位置;
2020 // 編集モードオブジェクトへ処理を引き継ぐ。
2022 this.編集モード.PreviewKeyDown( e );
2026 protected void splitContainer分割パネルコンテナ_MouseWheel( object sender, MouseEventArgs e )
2028 if( false == this.初期化完了 )
2029 return; // 初期化が終わってないのに呼び出されることがあるので、その場合は無視。
2031 #region " 移動量に対応する grid だけ垂直つまみを移動させる。あとはこの移動で生じる ChangedValue イベントで処理する。"
2036 // e.Delta は、スクロールバーを下へ動かしたいときに負、上へ動かしたいときに正となる。
2037 int 移動すべき行数 = ( -e.Delta * SystemInformation.MouseWheelScrollLines ) / 120;
2040 int 移動すべき数grid = 移動すべき行数 * ( this.GRID_PER_PART / 4 );
2042 // スクロールバーのつまみを移動する。
2043 int 新しい位置 = this.vScrollBar譜面用垂直スクロールバー.Value + 移動すべき数grid;
2044 int 最小値 = this.vScrollBar譜面用垂直スクロールバー.Minimum;
2045 int 最大値 = ( this.vScrollBar譜面用垂直スクロールバー.Maximum + 1 ) - this.vScrollBar譜面用垂直スクロールバー.LargeChange;
2051 else if( 新しい位置 > 最大値 )
2055 this.vScrollBar譜面用垂直スクロールバー.Value = 新しい位置;
2059 protected void splitContainer分割パネルコンテナ_Panel2_SizeChanged( object sender, EventArgs e )
2061 if( false == this.初期化完了 )
2062 return; // 初期化が終わってないのに呼び出されることがあるので、その場合は無視。
2064 this.垂直スクロールバーと譜面の上下位置を調整する();
2066 protected void splitContainer分割パネルコンテナ_Panel2_Paint( object sender, PaintEventArgs e )
2068 if( false == this.初期化完了 )
2069 return; // 初期化が終わってないのに呼び出されることがあるので、その場合は無視。
2072 var メモ領域左上隅の位置 = new PointF() {
2073 X = this.譜面.レーンの合計幅px,
2074 Y = this.pictureBox譜面パネル.Location.Y,
2077 #region " 見出し<小節メモ>を描画する。"
2079 g.DrawString( Properties.Resources.MSG_小節メモ, this.メモ用フォント, Brushes.White, PointF.Add( メモ領域左上隅の位置, new Size( 24, -24 )/*マージン*/ ) );
2082 #region " 小節メモを描画する。"
2085 // グリッド値は 上辺>下辺 なので注意。
2086 int パネル下辺grid = this.譜面.現在の譜面表示下辺の譜面内絶対位置grid;
2087 int パネル上辺grid = パネル下辺grid + ( this.pictureBox譜面パネル.ClientSize.Height * this.GRID_PER_PIXEL );
2088 int 開始小節番号 = this.譜面.現在譜面表示下辺に存在している小節番号;
2090 for( int 小節番号 = 開始小節番号; 小節番号 <= this.譜面.SSTFormatScore.最大小節番号; 小節番号++ )
2092 int 小節の下辺grid = this.譜面.小節先頭の譜面内絶対位置gridを返す( 小節番号 );
2093 int 小節の上辺grid = 小節の下辺grid + this.譜面.小節長をグリッドで返す( 小節番号 );
2095 if( 小節の下辺grid > パネル上辺grid )
2096 break; // 小節が画面上方にはみ出し切ってしまったらそこで終了。
2098 if( this.譜面.SSTFormatScore.dicメモ.ContainsKey( 小節番号 ) )
2100 string メモ = this.譜面.SSTFormatScore.dicメモ[ 小節番号 ];
2102 string[] lines = メモ.Split( new string[] { Environment.NewLine }, StringSplitOptions.None );
2103 int 行数 = lines.Length;
2105 var メモの位置 = new PointF() {
2106 X = メモ領域左上隅の位置.X + 4, // + 4 はマージン
2107 Y = メモ領域左上隅の位置.Y + ( パネル上辺grid - 小節の下辺grid ) / this.GRID_PER_PIXEL - ( 行数 * 16 ), // 9pt = だいたい16px
2109 g.DrawString( メモ, this.メモ用フォント, Brushes.White, メモの位置 );
2116 protected void vScrollBar譜面用垂直スクロールバー_ValueChanged( object sender, EventArgs e )
2118 if( false == this.初期化完了 )
2119 return; // 初期化が終わってないのに呼び出されることがあるので、その場合は無視。
2121 var bar = vScrollBar譜面用垂直スクロールバー;
2126 this.譜面.現在の譜面表示下辺の譜面内絶対位置grid = ( ( bar.Maximum + 1 ) - bar.LargeChange ) - bar.Value;
2128 // 編集モードの場合、カーソルのgrid位置を再計算。
2131 this.編集モード.MouseMove(
2132 new MouseEventArgs( MouseButtons.None, 0, this.編集モード.現在のチップカーソル領域.X, this.編集モード.現在のチップカーソル領域.Y, 0 ) );
2136 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2137 this.numericUpDownメモ用小節番号.Value = this.譜面.現在カレントラインに存在している小節番号;
2138 this.次のプロパティ変更がUndoRedoリストに載るようにする();
2141 this.splitContainer分割パネルコンテナ.Panel2.Refresh();
2148 protected void toolStripMenuItem選択チップの切り取り_Click( object sender, EventArgs e )
2152 protected void toolStripMenuItem選択チップのコピー_Click( object sender, EventArgs e )
2156 protected void toolStripMenuItem選択チップの貼り付け_Click( object sender, EventArgs e )
2158 // メニューが開かれたときのマウスの座標を取得。
2159 // ※メニューは必ずマウス位置を左上にして表示されるとは限らないため、メニューの表示位置からは取得しないこと。
2160 var マウスの位置 = this.選択モードのコンテクストメニューを開いたときのマウスの位置;
2162 if( this.譜面.譜面パネル内X座標pxにある編集レーンを返す( マウスの位置.X ) == 編集レーン種別.Unknown )
2163 return; // クリックされた場所にレーンがないなら無視。
2166 this.Act貼り付ける( this.譜面.譜面パネル内Y座標pxにおける譜面内絶対位置gridをガイド幅単位で返す( マウスの位置.Y ) );
2168 protected void toolStripMenuItem選択チップの削除_Click( object sender, EventArgs e )
2172 protected void toolStripMenuItemすべてのチップの選択_Click( object sender, EventArgs e )
2174 // 編集モードなら強制的に選択モードにする。
2176 this.選択モードに切替えて関連GUIを設定する();
2179 this.選択モード.全チップを選択する();
2181 protected void toolStripMenuItem小節長変更_Click( object sender, EventArgs e )
2183 // メニューが開かれたときのマウスの座標を取得。
2184 // ※メニューは必ずマウス位置を左上にして表示されるとは限らないため、メニューの表示位置からは取得しないこと。
2185 var マウスの位置 = this.選択モードのコンテクストメニューを開いたときのマウスの位置;
2187 if( this.譜面.譜面パネル内X座標pxにある編集レーンを返す( マウスの位置.X ) == 編集レーン種別.Unknown )
2188 return; // クリックされた場所にレーンがないなら無視。
2191 this.Act小節長倍率を変更する( this.譜面.譜面パネル内Y座標pxにおける小節番号を返す( マウスの位置.Y ) );
2193 protected void toolStripMenuItem小節の挿入_Click( object sender, EventArgs e )
2195 // メニューが開かれたときのマウスの座標を取得。
2196 // ※メニューは必ずマウス位置を左上にして表示されるとは限らないため、メニューの表示位置からは取得しないこと。
2197 var マウスの位置 = this.選択モードのコンテクストメニューを開いたときのマウスの位置;
2199 if( this.譜面.譜面パネル内X座標pxにある編集レーンを返す( マウスの位置.X ) == 編集レーン種別.Unknown )
2200 return; // クリックされた場所にレーンがないなら無視。
2203 this.Act小節を挿入する( this.譜面.譜面パネル内Y座標pxにおける小節番号を返す( マウスの位置.Y ) );
2205 protected void toolStripMenuItem小節の削除_Click( object sender, EventArgs e )
2207 // メニューが開かれたときのマウスの座標を取得。
2208 // ※メニューは必ずマウス位置を左上にして表示されるとは限らないため、メニューの表示位置からは取得しないこと。
2209 var マウスの位置 = this.選択モードのコンテクストメニューを開いたときのマウスの位置;
2211 if( this.譜面.譜面パネル内X座標pxにある編集レーンを返す( マウスの位置.X ) == 編集レーン種別.Unknown )
2212 return; // クリックされた場所にレーンがないなら無視。
2215 this.Act小節を削除する( this.譜面.譜面パネル内Y座標pxにおける小節番号を返す( マウスの位置.Y ) );
2221 protected void textBox曲名_TextChanged( object sender, EventArgs e )
2223 #region " この変更が Undo/Redo したことによるものではない場合、UndoRedoセルを追加 or 修正する。"
2225 if( false == UndoRedo.管理.UndoRedoした直後である )
2228 var cell = this.UndoRedo管理.Undoするセルを取得して返す_見るだけ();
2230 if( ( null != cell ) && cell.所有権がある( this.textBox曲名 ) )
2232 // (A) 所有者である → 最新のセルの "変更後の値" を現在のコントロールの値に更新する。
2233 ( (UndoRedo.セル<string>) cell ).変更後の値 = this.textBox曲名.Text;
2237 // (B) 所有者ではない → 以下のようにセルを新規追加する。
2240 // "所有者ID" ← 対象となるコンポーネントオブジェクト
2241 var cc = new UndoRedo.セル<string>(
2242 所有者ID: this.textBox曲名,
2243 Undoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
2244 this.タブを選択する( タブ種別.基本情報 );
2245 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2246 this.textBox曲名.Text = 変更前;
2247 this.textBox曲名.Focus();
2249 Redoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
2250 this.タブを選択する( タブ種別.基本情報 );
2251 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2252 this.textBox曲名.Text = 変更後;
2253 this.textBox曲名.Focus();
2256 変更前の値: this.textBox曲名_以前の値,
2257 変更後の値: this.textBox曲名.Text,
2261 this.UndoRedo管理.セルを追加する( cc );
2264 this.UndoRedo用GUIのEnabledを設定する();
2270 this.textBox曲名_以前の値 = this.textBox曲名.Text; // 以前の値 ← 現在の値
2271 UndoRedo.管理.UndoRedoした直後である = false;
2275 譜面.SSTFormatScore.Header.曲名 = this.textBox曲名.Text;
2277 protected void textBox曲名_Leave( object sender, EventArgs e )
2279 // 最新の UndoRedoセル の所有権を放棄する。
2280 this.UndoRedo管理.Undoするセルを取得して返す_見るだけ()?.所有権を放棄する( this.textBox曲名 );
2282 protected string textBox曲名_以前の値 = "";
2284 protected void textBox説明_TextChanged( object sender, EventArgs e )
2286 #region " この変更が Undo/Redo したことによるものではない場合、UndoRedoセルを追加 or 修正する。"
2288 if( false == UndoRedo.管理.UndoRedoした直後である )
2291 var cell = this.UndoRedo管理.Undoするセルを取得して返す_見るだけ();
2292 if( ( null != cell ) && cell.所有権がある( this.textBox説明 ) )
2294 // (A) 所有者である → 最新のセルの "変更後の値" を現在のコントロールの値に更新。
2296 ( (UndoRedo.セル<string>) cell ).変更後の値 = this.textBox説明.Text;
2300 // (B) 所有者ではない → 以下のようにセルを新規追加する。
2303 // "所有者ID" ← 対象となるコンポーネントオブジェクト
2304 var cc = new UndoRedo.セル<string>(
2305 所有者ID: this.textBox説明,
2306 Undoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
2307 this.タブを選択する( タブ種別.基本情報 );
2308 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2309 this.textBox説明.Text = 変更前;
2310 this.textBox説明.Focus();
2312 Redoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
2313 this.タブを選択する( タブ種別.基本情報 );
2314 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2315 this.textBox説明.Text = 変更後;
2316 this.textBox説明.Focus();
2319 変更前の値: this.textBox説明_以前の値,
2320 変更後の値: this.textBox説明.Text,
2324 this.UndoRedo管理.セルを追加する( cc );
2327 this.UndoRedo用GUIのEnabledを設定する();
2333 this.textBox説明_以前の値 = this.textBox説明.Text; // 以前の値 ← 現在の値
2334 UndoRedo.管理.UndoRedoした直後である = false;
2338 譜面.SSTFormatScore.Header.説明文 = this.textBox説明.Text;
2340 protected void textBox説明_Leave( object sender, EventArgs e )
2342 // 最新 UndoRedoセル の所有権を放棄する。
2343 this.UndoRedo管理.Undoするセルを取得して返す_見るだけ()?.所有権を放棄する( this.textBox説明 );
2345 protected string textBox説明_以前の値 = "";
2347 protected void textBoxメモ_TextChanged( object sender, EventArgs e )
2349 #region " この変更が Undo/Redo したことによるものではない場合、UndoRedoセルを追加or修正する。"
2351 if( !UndoRedo.管理.UndoRedoした直後である )
2355 UndoRedo.セルBase cell = this.UndoRedo管理.Undoするセルを取得して返す_見るだけ();
2357 if( ( cell != null ) && cell.所有権がある( this.textBoxメモ ) )
2359 // (Yes) 最新のセルの "変更後の値" を <現在の値> に更新。
2361 ( (UndoRedo.セル<string>) cell ).変更後の値 = this.textBoxメモ.Text;
2368 // "所有者ID" = 対象となるコンポーネントオブジェクト
2370 var cc = new UndoRedo.セル<string>(
2371 所有者ID: this.textBoxメモ,
2372 Undoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
2373 this.タブを選択する( タブ種別.基本情報 );
2374 this.numericUpDownメモ用小節番号.Value = (decimal) 任意1;
2375 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2376 this.textBoxメモ.Text = 変更前;
2377 this.textBoxメモ.Focus();
2379 int 小節番号 = (int) ( (decimal) 任意1 );
2381 #region " dicメモ の更新 "
2383 if( this.譜面.SSTFormatScore.dicメモ.ContainsKey( 小節番号 ) )
2385 if( string.IsNullOrEmpty( 変更前 ) )
2386 this.譜面.SSTFormatScore.dicメモ.Remove( 小節番号 );
2388 this.譜面.SSTFormatScore.dicメモ[ 小節番号 ] = 変更前;
2392 if( !string.IsNullOrEmpty( 変更前 ) )
2393 this.譜面.SSTFormatScore.dicメモ.Add( 小節番号, 変更前 );
2398 this.Act小節の先頭へ移動する( 小節番号 );
2399 this.splitContainer分割パネルコンテナ.Panel2.Refresh(); // 小節メモをリフレッシュ。
2401 Redoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
2402 this.タブを選択する( タブ種別.基本情報 );
2403 this.numericUpDownメモ用小節番号.Value = (decimal) 任意1;
2404 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2405 this.textBoxメモ.Text = 変更後;
2406 this.textBoxメモ.Focus();
2408 int 小節番号 = (int) ( (decimal) 任意1 );
2410 #region " dicメモの更新 "
2412 if( this.譜面.SSTFormatScore.dicメモ.ContainsKey( 小節番号 ) )
2414 if( string.IsNullOrEmpty( 変更後 ) )
2415 this.譜面.SSTFormatScore.dicメモ.Remove( 小節番号 );
2417 this.譜面.SSTFormatScore.dicメモ[ 小節番号 ] = 変更後;
2421 if( !string.IsNullOrEmpty( 変更後 ) )
2422 this.譜面.SSTFormatScore.dicメモ.Add( 小節番号, 変更後 );
2427 this.Act小節の先頭へ移動する( 小節番号 );
2428 this.splitContainer分割パネルコンテナ.Panel2.Refresh(); // 小節メモをリフレッシュ。
2431 変更前の値: this.textBoxメモ_以前の値,
2432 変更後の値: this.textBoxメモ.Text,
2433 任意1: (object) this.numericUpDownメモ用小節番号.Value,
2436 this.UndoRedo管理.セルを追加する( cc );
2439 this.UndoRedo用GUIのEnabledを設定する();
2445 this.textBoxメモ_以前の値 = this.textBoxメモ.Text; // <以前の値> = <現在の値>
2447 if( false == UndoRedo.管理.UndoRedoした直後である )
2450 UndoRedo.管理.UndoRedoした直後である = false;
2452 #region " 小節番号に対応するメモを dicメモ に登録する。"
2455 int 小節番号 = (int) this.numericUpDownメモ用小節番号.Value;
2457 if( string.IsNullOrEmpty( this.textBoxメモ.Text ) )
2460 if( this.譜面.SSTFormatScore.dicメモ.ContainsKey( 小節番号 ) )
2461 this.譜面.SSTFormatScore.dicメモ.Remove( 小節番号 ); // 存在してたら削除。
2467 if( this.譜面.SSTFormatScore.dicメモ.ContainsKey( 小節番号 ) )
2468 this.譜面.SSTFormatScore.dicメモ[ 小節番号 ] = this.textBoxメモ.Text; // 存在してたら更新。
2470 this.譜面.SSTFormatScore.dicメモ.Add( 小節番号, this.textBoxメモ.Text ); // 存在してなかったら追加。
2475 #region " もし最終小節だったなら、後ろに4つ小節を加える。"
2478 int 小節番号 = (int) this.numericUpDownメモ用小節番号.Value;
2479 if( 小節番号 == this.譜面.SSTFormatScore.最大小節番号 )
2481 this.譜面.最後の小節の後ろに小節を4つ追加する();
2487 protected void textBoxメモ_Leave( object sender, EventArgs e )
2489 // 最新 UndoRedoセル の所有権を放棄する。
2490 this.UndoRedo管理.Undoするセルを取得して返す_見るだけ()?.所有権を放棄する( this.textBoxメモ );
2493 this.splitContainer分割パネルコンテナ.Panel2.Refresh();
2495 protected string textBoxメモ_以前の値 = "";
2497 protected void numericUpDownメモ用小節番号_ValueChanged( object sender, EventArgs e )
2499 // 小節番号にあわせて、textBoxメモにメモを表示する。
2500 int 小節番号 = (int) this.numericUpDownメモ用小節番号.Value;
2501 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2502 if( this.譜面.SSTFormatScore.dicメモ.ContainsKey( 小節番号 ) )
2503 this.textBoxメモ.Text = this.譜面.SSTFormatScore.dicメモ[ 小節番号 ];
2505 this.textBoxメモ.Text = "";
2506 this.次のプロパティ変更がUndoRedoリストに載るようにする();
2511 private Font メモ用フォント = new Font( FontFamily.GenericSansSerif, 9.0f );
2512 private readonly Dictionary<int, string> dic音量ラベル = new Dictionary<int, string>() {
2513 { 1, "1 (Smallest)" },
2514 { 2, "2 (Smaller)" },
2515 { 3, "3 (Middle)" },
2516 { 4, "4 (Normal)" },