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 仮想ドラムオプション = ( 仮想ドラムを使う ) ? @" -d" : @"";
770 this.Config.ViewerPath,
771 $"\"{this.最後にプレイヤーに渡した一時ファイル名}\" -p {小節番号.ToString()}{仮想ドラムオプション}" );
774 protected void Act再生を停止する()
776 if( this.Config.ViewerPath.Nullまたは空である() ||
777 ( false == File.Exists( this.Config.ViewerPath ) ) )
780 // プレイヤーを、演奏停止オプションをつけて起動する。
781 Process.Start( this.Config.ViewerPath, @"-s" );
783 protected void Actオプションを設定する()
785 using( var dialog = new オプションダイアログ() )
787 // Config の現在の値をダイアログへ反映する。
788 dialog.checkBoxオートフォーカス.CheckState = ( this.Config.AutoFocus ) ? CheckState.Checked : CheckState.Unchecked;
789 dialog.checkBox最近使用したファイル.CheckState = ( this.Config.ShowRecentUsedFiles ) ? CheckState.Checked : CheckState.Unchecked;
790 dialog.numericUpDown最近使用したファイルの最大表示個数.Value = this.Config.MaxOfUsedRecentFiles;
791 dialog.textBoxViewerPath.Text = this.Config.ViewerPath;
793 if( DialogResult.OK == dialog.ShowDialog( this ) )
795 // 決定された値をダイアログから Config に反映する。
796 this.Config.AutoFocus = dialog.checkBoxオートフォーカス.Checked;
797 this.Config.ShowRecentUsedFiles = dialog.checkBox最近使用したファイル.Checked;
798 this.Config.MaxOfUsedRecentFiles = (int) dialog.numericUpDown最近使用したファイルの最大表示個数.Value;
799 this.Config.ViewerPath = dialog.textBoxViewerPath.Text;
802 this.ConfigのRecentUsedFilesをファイルメニューへ追加する();
805 this.Config.保存する( Path.Combine( this.ユーザフォルダパス, Properties.Resources.CONFIG_FILE_NAME ) );
809 // 画面を再描画してダイアログのゴミを消す。
812 protected void Actバージョンを表示する()
814 using( var dialog = new バージョン表示ダイアログ() )
815 dialog.ShowDialog( this );
817 protected void Act小節長倍率を変更する( int 小節番号 )
823 #region " 変更後の小節長倍率をユーザに入力させる。"
825 var db現在の小節長倍率 = this.譜面.SSTFormatScore.小節長倍率を取得する( 小節番号 );
826 using( var dialog = new 小節長倍率入力ダイアログ( 小節番号 ) )
828 dialog.倍率 = (float) db現在の小節長倍率;
829 dialog.後続も全部変更する = false;
831 if( DialogResult.OK != dialog.ShowDialog( this ) ) // キャンセルされたらここで中断。
834 変更後倍率 = (double) dialog.倍率;
835 変更終了小節番号 = ( dialog.後続も全部変更する ) ? this.譜面.SSTFormatScore.最大小節番号 : 小節番号;
843 this.UndoRedo管理.トランザクション記録を開始する();
845 for( int i = 変更開始小節番号; i <= 変更終了小節番号; i++ )
847 var 変更前倍率 = this.譜面.SSTFormatScore.小節長倍率を取得する( i );
849 #region " 新しい小節長倍率を設定する。"
851 var cell = new UndoRedo.セル<double>(
853 Undoアクション: ( 変更対象, 変更前, 変更後, 対象小節番号, 任意2 ) => {
854 this.譜面.SSTFormatScore.小節長倍率を設定する( (int) 対象小節番号, 変更前 );
857 Redoアクション: ( 変更対象, 変更前, 変更後, 対象小節番号, 任意2 ) => {
858 this.譜面.SSTFormatScore.小節長倍率を設定する( (int) 対象小節番号, 変更後 );
867 this.UndoRedo管理.セルを追加する( cell );
871 #region " チップを移動または削除する。"
873 int 変化量grid = (int) ( ( 変更後倍率 - 変更前倍率 ) * this.GRID_PER_PART );
875 for( int j = this.譜面.SSTFormatScore.チップリスト.Count - 1; j >= 0; j-- ) // 削除する場合があるので後ろからカウントする。
877 var chip = this.譜面.SSTFormatScore.チップリスト[ j ];
879 // (A) 変更対象の小節内のチップ → 移動なし。カウント変更あり。小節はみ出しチェックあり。
882 #region " 小節からはみ出したチップは、削除する。"
884 int 次小節の先頭位置grid = this.譜面.小節先頭の譜面内絶対位置gridを返す( i ) + (int) ( 変更後倍率 * this.GRID_PER_PART );
885 if( 次小節の先頭位置grid <= chip.譜面内絶対位置grid )
887 var chip変更前 = new SSTFormat.チップ( chip );
889 var cc = new UndoRedo.セル<SSTFormat.チップ>(
891 Undoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
892 変更対象.CopyFrom( 変更前 );
893 this.譜面.SSTFormatScore.チップリスト.Add( 変更対象 );
894 this.譜面.SSTFormatScore.チップリスト.Sort();
897 Redoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
898 this.譜面.SSTFormatScore.チップリスト.Remove( 変更対象 );
907 this.UndoRedo管理.セルを追加する( cc );
912 #region " 小節からはみ出さなかったチップは、カウント(小節解像度と小節内位置)を変更する。"
916 // 解像度が小さいと計算結果がおかしくなるので、無条件に解像度を上げる。
918 int 十分に大きな値 = this.GRID_PER_PART; // 充分に大きい数なら何でもいい。
919 if( 十分に大きな値 > chip.小節解像度 ) // 何度も乗算されたら値が肥大化しまくるので、制限をかける。
921 chip.小節解像度 *= 十分に大きな値;
922 chip.小節内位置 *= 十分に大きな値;
925 // 小節解像度を変更する。(小節内位置は変更しない。)
926 chip.小節解像度 = (int) ( 変更後倍率 * chip.小節解像度 );
932 // (B) 変更対象より先の小節内のチップ → 移動あり。カウントなし。小節はみ出しチェックなし。
933 else if( i < chip.小節番号 )
935 #region " チップを n変化量grid 移動する。"
937 var cc = new UndoRedo.セル<SSTFormat.チップ>(
939 Undoアクション: ( 変更対象, 変更前, 変更後, _変化量grid, 任意2 ) => {
940 変更対象.譜面内絶対位置grid -= (int) _変化量grid;
943 Redoアクション: ( 変更対象, 変更前, 変更後, _変化量grid, 任意2 ) => {
944 変更対象.譜面内絶対位置grid += (int) _変化量grid;
953 this.UndoRedo管理.セルを追加する( cc );
965 this.UndoRedo管理.トランザクション記録を終了する();
968 this.UndoRedo用GUIのEnabledを設定する();
972 protected void Act小節を挿入する( int 挿入前小節番号 )
974 // 挿入する新しい小節の小節長は、直前の(挿入前小節番号-1 の小節)と同じサイズとする。
975 double 小節長倍率 = ( 0 < 挿入前小節番号 ) ? this.譜面.SSTFormatScore.小節長倍率を取得する( 挿入前小節番号 - 1 ) : 1.0;
980 this.UndoRedo管理.トランザクション記録を開始する();
982 #region " 後方のチップを移動する。"
984 int 挿入に伴う増加量grid = (int) ( this.GRID_PER_PART * 小節長倍率 );
986 foreach( var chip in this.譜面.SSTFormatScore.チップリスト )
988 if( 挿入前小節番号 <= chip.小節番号 )
990 var cell = new UndoRedo.セル<SSTFormat.チップ>(
992 Undoアクション: ( 変更対象, 変更前, 変更後, _挿入に伴う増加量grid, 任意2 ) => {
994 変更対象.譜面内絶対位置grid -= (int) _挿入に伴う増加量grid;
996 Redoアクション: ( 変更対象, 変更前, 変更後, _挿入に伴う増加量grid, 任意2 ) => {
998 変更対象.譜面内絶対位置grid += (int) _挿入に伴う増加量grid;
1006 this.UndoRedo管理.セルを追加する( cell );
1012 #region " 後方の小節長倍率を移動する。"
1014 var cc = new UndoRedo.セル<double>(
1016 Undoアクション: ( 変更対象, 変更前, 変更後, _挿入前小節番号, 任意2 ) => {
1017 this.譜面.SSTFormatScore.小節長倍率リスト.RemoveAt( (int) _挿入前小節番号 );
1020 Redoアクション: ( 変更対象, 変更前, 変更後, _挿入前小節番号, 任意2 ) => {
1021 this.譜面.SSTFormatScore.小節長倍率リスト.Insert( (int) _挿入前小節番号, 小節長倍率 );
1030 this.UndoRedo管理.セルを追加する( cc );
1037 this.UndoRedo管理.トランザクション記録を終了する();
1040 this.UndoRedo用GUIのEnabledを設定する();
1045 protected void Act小節を削除する( int 削除する小節番号 )
1047 double 削除する小節の小節長倍率 = this.譜面.SSTFormatScore.小節長倍率を取得する( 削除する小節番号 );
1052 this.UndoRedo管理.トランザクション記録を開始する();
1054 #region " 削除される小節内のチップをすべて削除する。"
1056 for( int i = this.譜面.SSTFormatScore.チップリスト.Count - 1; i >= 0; i-- )
1058 var chip = this.譜面.SSTFormatScore.チップリスト[ i ];
1060 if( 削除する小節番号 == chip.小節番号 )
1062 var chip変更前 = new SSTFormat.チップ( chip );
1064 var cell = new UndoRedo.セル<SSTFormat.チップ>(
1066 Undoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
1067 変更対象.CopyFrom( 変更前 );
1068 this.譜面.SSTFormatScore.チップリスト.Add( 変更対象 );
1069 this.譜面.SSTFormatScore.チップリスト.Sort();
1071 Redoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
1072 this.譜面.SSTFormatScore.チップリスト.Remove( 変更対象 );
1081 this.UndoRedo管理.セルを追加する( cell );
1087 #region " 後方のチップを移動する。"
1089 int 削除に伴う減少量grid = (int) ( this.GRID_PER_PART * 削除する小節の小節長倍率 );
1091 foreach( var chip in this.譜面.SSTFormatScore.チップリスト )
1093 if( 削除する小節番号 < chip.小節番号 )
1095 var cell = new UndoRedo.セル<SSTFormat.チップ>(
1097 Undoアクション: ( 変更対象, 変更前, 変更後, _削除に伴う減少量grid, 任意2 ) => {
1099 変更対象.譜面内絶対位置grid += (int) _削除に伴う減少量grid;
1101 Redoアクション: ( 変更対象, 変更前, 変更後, _削除に伴う減少量grid, 任意2 ) => {
1103 変更対象.譜面内絶対位置grid -= (int) _削除に伴う減少量grid;
1111 this.UndoRedo管理.セルを追加する( cell );
1117 #region " 後方の小節長倍率を移動する。"
1119 var cc = new UndoRedo.セル<double>(
1121 Undoアクション: ( 変更対象, 変更前, 変更後, _削除する小節番号, 任意2 ) => {
1122 this.譜面.SSTFormatScore.小節長倍率リスト.Insert( (int) _削除する小節番号, 変更前 );
1125 Redoアクション: ( 変更対象, 変更前, 変更後, _削除する小節番号, 任意2 ) => {
1126 this.譜面.SSTFormatScore.小節長倍率リスト.RemoveAt( (int) _削除する小節番号 );
1130 変更前の値: 削除する小節の小節長倍率,
1135 this.UndoRedo管理.セルを追加する( cc );
1142 this.UndoRedo管理.トランザクション記録を終了する();
1145 this.UndoRedo用GUIのEnabledを設定する();
1149 protected void Act小節の先頭へ移動する( int 小節番号 )
1154 else if( 小節番号 > this.譜面.SSTFormatScore.最大小節番号 )
1155 小節番号 = this.譜面.SSTFormatScore.最大小節番号;
1157 // 垂直スクロールバーを移動させると、画面も自動的に移動する。
1158 var bar = this.vScrollBar譜面用垂直スクロールバー;
1159 bar.Value = ( ( bar.Maximum + 1 ) - bar.LargeChange ) - this.譜面.小節先頭の譜面内絶対位置gridを返す( 小節番号 );
1164 protected void エディタを初期化する()
1166 this.編集中のファイル名 = null;
1168 #region " 各種オブジェクトを生成する。"
1171 this.譜面 = new C譜面( this ); // 譜面は、選択・編集モードよりも先に生成すること。
1173 this.UndoRedo管理 = new UndoRedo.管理();
1174 this.選択モード = new 選択モード( this );
1175 this.編集モード = new 編集モード( this );
1176 this.クリップボード = new クリップボード( this );
1184 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
1185 this.textBox曲名.Clear();
1187 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
1188 this.textBox説明.Clear();
1191 #region " Viewer 再生 "
1193 this.Viewer再生関連GUIのEnabledを設定する();
1198 this.Actガイド間隔を変更する( 16 ); // 初期値は 1/16。
1203 this.Act譜面拡大率を変更する( 1 ); // 初期値は x1.0。
1206 #region " Undo/Redo "
1208 this.次のプロパティ変更がUndoRedoリストに載るようにする();
1209 this.UndoRedo用GUIのEnabledを設定する();
1212 #region " 垂直スクロールバー "
1214 this.vScrollBar譜面用垂直スクロールバー.Minimum = 0;
1215 this.vScrollBar譜面用垂直スクロールバー.Maximum = ( this.譜面.全小節の高さgrid - 1 );
1216 this.vScrollBar譜面用垂直スクロールバー.SmallChange = ( this.GRID_PER_PART / 16 );
1217 this.vScrollBar譜面用垂直スクロールバー.LargeChange = this.GRID_PER_PART;
1218 this.vScrollBar譜面用垂直スクロールバー.Value = this.vScrollBar譜面用垂直スクロールバー.Maximum - this.vScrollBar譜面用垂直スクロールバー.LargeChange;
1224 this.編集モードに切替えて関連GUIを設定する();
1225 this.未保存である = false;
1227 protected DialogResult 未保存なら保存する()
1229 #region " 既に保存済みなら何もしない。"
1231 if( false == this.未保存である )
1232 return DialogResult.OK;
1235 #region "[編集中のデータを保存しますか?] ダイアログを表示し、回答を待つ。"
1237 var result = MessageBox.Show(
1238 Properties.Resources.MSG_編集中のデータを保存しますか,
1239 Properties.Resources.MSG_確認ダイアログのタイトル,
1240 MessageBoxButtons.YesNoCancel,
1241 MessageBoxIcon.Question,
1242 MessageBoxDefaultButton.Button1 );
1245 #region " YES なら上書き保存する。"
1247 if( DialogResult.Yes == result )
1251 #region " 画面を再描画してダイアログを消去する。"
1257 return result; // ダイアログの結果を返す。
1259 protected string ファイル保存ダイアログを開いてファイル名を取得する()
1261 DialogResult result;
1264 // ダイアログでファイル名を取得する。
1265 using( var dialog = new SaveFileDialog() {
1267 Filter = "SSTFファイル(*.sstf)|*.sstf",
1269 InitialDirectory = this.作業フォルダパス,
1272 result = dialog.ShowDialog( this );
1273 ファイル名 = dialog.FileName;
1276 // 画面を再描画してダイアログのゴミを消去する。
1279 // キャンセルされたら ""(空文字列)を返す。
1280 if( DialogResult.OK != result )
1283 // ファイルの拡張子を .sstf に変更。
1284 if( 0 == Path.GetExtension( ファイル名 ).Length )
1285 ファイル名 = Path.ChangeExtension( ファイル名, ".sstf" );
1289 protected void ファイルを読み込む( string ファイル名 )
1293 #region " [読み込み中です] ポップアップを表示する。"
1295 var msg = new Popupメッセージ(
1296 Properties.Resources.MSG_読み込み中です + Environment.NewLine +
1297 Properties.Resources.MSG_しばらくお待ち下さい );
1306 this.譜面.曲データファイルを読み込む( ファイル名 );
1308 // 最低でも 10 小節は存在させる。
1309 for( int n = this.譜面.SSTFormatScore.最大小節番号 + 1; n < 9; n++ )
1312 string 読み込み時の拡張子 = Path.GetExtension( ファイル名 ).ToLower();
1313 this.編集中のファイル名 = Path.ChangeExtension( Path.GetFileName( ファイル名 ), ".sstf" ); // 読み込んだファイルの拡張子を .sstf に変換。
1314 this.作業フォルダパス = Path.GetDirectoryName( ファイル名 );
1316 // 読み込んだファイルを [ファイル]メニューの最近使ったファイル一覧に追加する。
1317 this.Config.ファイルを最近使ったファイルの一覧に追加する( Path.Combine( this.作業フォルダパス, this.編集中のファイル名 ) );
1318 this.ConfigのRecentUsedFilesをファイルメニューへ追加する();
1321 譜面.SSTFormatScore.背景動画ファイル名 =
1322 ( from file in Directory.GetFiles( Path.GetDirectoryName( this.作業フォルダパス ) )
1323 where SSTFormat.スコア.背景動画のデフォルト拡張子s.Any( 拡張子名 => ( Path.GetExtension( file ).ToLower() == 拡張子名 ) )
1324 select file ).FirstOrDefault(); // 複数あったら、最初に見つけたほうを採用。1つも見つからなければ null。
1325 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
1326 this.textBox曲名.Text = 譜面.SSTFormatScore.Header.曲名;
1327 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
1328 this.textBox説明.Text = 譜面.SSTFormatScore.Header.説明文;
1329 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
1330 this.textBox背景動画.Text = Path.GetFileName( 譜面.SSTFormatScore.背景動画ファイル名 );
1331 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
1332 this.textBoxメモ.Text = ( this.譜面.SSTFormatScore.dicメモ.ContainsKey( 0 ) ) ? this.譜面.SSTFormatScore.dicメモ[ 0 ] : "";
1334 // ウィンドウのタイトルバーの表示変更(str編集中のファイル名 が確定した後に)
1335 this.未保存である = true; // 以前の状態によらず、確実に更新するようにする。
1337 // sstf 以外を読み込んだ場合は、未保存状態のままとする。
1338 if( 読み込み時の拡張子.ToLower() == ".sstf" )
1339 this.未保存である = false;
1341 catch( InvalidDataException )
1344 Properties.Resources.MSG_対応していないファイルです,
1345 Properties.Resources.MSG_確認ダイアログのタイトル,
1346 MessageBoxButtons.OK );
1349 #region "「読み込み中です」ポップアップを閉じる。 "
1355 // 最後に、ダイアログのゴミなどを消すために画面を再描画する。
1358 protected enum タブ種別 : int { 基本情報 = 0 }
1359 protected void タブを選択する( タブ種別 eタブ種別 )
1361 this.tabControl情報タブコンテナ.SelectedIndex = (int) eタブ種別;
1363 protected void 次のプロパティ変更がUndoRedoリストに載らないようにする()
1365 UndoRedo.管理.UndoRedoした直後である = true;
1367 protected void 次のプロパティ変更がUndoRedoリストに載るようにする()
1369 UndoRedo.管理.UndoRedoした直後である = false;
1371 protected void 垂直スクロールバーと譜面の上下位置を調整する()
1373 var bar = this.vScrollBar譜面用垂直スクロールバー;
1374 var box = this.pictureBox譜面パネル;
1375 var panel2 = this.splitContainer分割パネルコンテナ.Panel2;
1377 // 譜面パネルの長さをパネルに合わせて調整する。
1378 box.ClientSize = new Size(
1379 box.ClientSize.Width,
1380 panel2.ClientSize.Height - box.Location.Y );
1382 // 現在のバーの位置を割合で記憶する。
1383 var bar率 = (double) bar.Value / (double) ( bar.Maximum - bar.Minimum );
1385 // 新しい値域を設定した後、バーの位置を記憶しておいた割合で設定。
1387 bar.Maximum = this.譜面.全小節の高さgrid - 1;
1388 bar.Value = (int) ( ( bar.Maximum - bar.Minimum ) * bar率 );
1390 // 譜面長さが画面長さより短いなら、スクロールバーを表示しない。
1391 bar.Enabled = ( bar.Maximum > bar.LargeChange ) ? true : false;
1393 protected void Viewer再生関連GUIのEnabledを設定する()
1395 if( File.Exists( this.Config.ViewerPath ) )
1397 // (A) Viewer が存在するなら、各GUIは有効。
1399 this.toolStripButton先頭から再生.Enabled = true;
1400 this.toolStripButton現在位置から再生.Enabled = true;
1401 this.toolStripButton現在位置からBGMのみ再生.Enabled = true;
1402 this.toolStripButton再生停止.Enabled = true;
1404 this.toolStripMenuItem先頭から再生.Enabled = true;
1405 this.toolStripMenuItem現在位置から再生.Enabled = true;
1406 this.toolStripMenuItem現在位置からBGMのみ再生.Enabled = true;
1407 this.toolStripMenuItem再生停止.Enabled = true;
1411 // (B) Viewer が存在しないなら、各GUIは無効。
1413 this.toolStripButton先頭から再生.Enabled = false;
1414 this.toolStripButton現在位置から再生.Enabled = false;
1415 this.toolStripButton現在位置からBGMのみ再生.Enabled = false;
1416 this.toolStripButton再生停止.Enabled = false;
1418 this.toolStripMenuItem先頭から再生.Enabled = false;
1419 this.toolStripMenuItem現在位置から再生.Enabled = false;
1420 this.toolStripMenuItem現在位置からBGMのみ再生.Enabled = false;
1421 this.toolStripMenuItem再生停止.Enabled = false;
1424 protected void ConfigのRecentUsedFilesをファイルメニューへ追加する()
1426 #region " [ファイル] メニューから、[最近使ったファイルの一覧] をクリアする。"
1428 for( int i = 0; i < this.toolStripMenuItemファイル.DropDownItems.Count; i++ )
1430 var item = this.toolStripMenuItemファイル.DropDownItems[ i ];
1432 // ↓削除したくないサブメニューの一覧。これ以外のサブメニュー項目はすべて削除する。
1433 if( item != this.toolStripMenuItem新規作成 &&
1434 item != this.toolStripMenuItem開く &&
1435 item != this.toolStripMenuItem上書き保存 &&
1436 item != this.toolStripMenuItem名前を付けて保存 &&
1437 item != this.toolStripSeparator1 &&
1438 item != this.toolStripMenuItem終了 )
1440 this.toolStripMenuItemファイル.DropDownItems.Remove( item );
1441 i = -1; // 要素数が変わったので列挙しなおし。RemoveAll() はないのか。
1447 if( ( false == this.Config.ShowRecentUsedFiles ) || // 表示しない or
1448 ( 0 == this.Config.RecentUsedFiles.Count ) ) // 履歴が 0 件
1451 #region " Config が持つ履歴にそって、[ファイル] メニューにサブメニュー項目リストを追加する(ただし最大表示数まで)。"
1453 // [File] のサブメニューリストに項目が1つでもある場合は、履歴サブメニュー項目を追加する前に、[終了] の下にセパレータを入れる。手動で。
1454 bool セパレータの追加がまだ = true;
1456 // すべての [最近使ったファイル] について...
1457 for( int i = 0; i < this.Config.RecentUsedFiles.Count; i++ )
1460 if( this.Config.MaxOfUsedRecentFiles <= i )
1463 // ファイルパスを、サブメニュー項目として [ファイル] メニューに追加する。
1464 string ファイルパス = this.Config.RecentUsedFiles[ i ];
1465 if( string.IsNullOrEmpty( ファイルパス ) )
1468 // セパレータの追加がまだなら追加する。
1471 this.toolStripMenuItemファイル.DropDownItems.Add( new ToolStripSeparator() { Size = this.toolStripSeparator1.Size } );
1472 セパレータの追加がまだ = false;
1475 // ToolStripMenuItem を手動で作って [ファイル] のサブメニューリストに追加する。
1476 var item = new ToolStripMenuItem() {
1477 Name = "最近使ったファイル" + i,
1478 Size = this.toolStripMenuItem終了.Size,
1479 Text = "&" + i + " " + ファイルパス,
1481 item.Click += new EventHandler( this.toolStripMenuItem最近使ったファイル_Click );
1482 this.toolStripMenuItemファイル.DropDownItems.Add( item );
1484 // 追加したファイルが既に存在していないなら項目を無効化(グレー表示)する。
1485 if( false == File.Exists( ファイルパス ) )
1486 item.Enabled = false;
1491 protected Point 現在のマウス位置を譜面パネル内座標pxに変換して返す()
1493 return this.pictureBox譜面パネル.PointToClient( new Point( Cursor.Position.X, Cursor.Position.Y ) );
1495 protected void 現在のチップ音量をツールバーに表示する()
1497 this.toolStripLabel音量.Text = ( this.dic音量ラベル.ContainsKey( this.現在のチップ音量 ) ) ? this.dic音量ラベル[ this.現在のチップ音量 ] : @"???";
1504 protected void メインフォーム_DragDrop( object sender, DragEventArgs e )
1506 string[] data = (string[]) e.Data.GetData( DataFormats.FileDrop );
1508 if( 1 <= data.Length )
1509 this.Act指定されたファイルを開く( data[ 0 ] ); // Dropされたファイルが複数個あっても、先頭のファイルだけを有効とする。
1511 protected void メインフォーム_DragEnter( object sender, DragEventArgs e )
1513 if( e.Data.GetDataPresent( DataFormats.FileDrop ) )
1515 e.Effect = DragDropEffects.Copy; // ファイルならコピーと見なす(カーソルがコピー型になる)
1519 e.Effect = DragDropEffects.None; // ファイルじゃないなら無視(カーソル変化なし)
1522 protected void メインフォーム_FormClosing( object sender, FormClosingEventArgs e )
1524 if( DialogResult.Cancel == this.未保存なら保存する() )
1538 protected void toolStripMenuItem新規作成_Click( object sender, EventArgs e )
1542 protected void toolStripMenuItem開く_Click( object sender, EventArgs e )
1546 protected void toolStripMenuItem上書き保存_Click( object sender, EventArgs e )
1550 protected void toolStripMenuItem名前を付けて保存_Click( object sender, EventArgs e )
1552 this.Act名前を付けて保存する();
1554 protected void toolStripMenuItem終了_Click( object sender, EventArgs e )
1558 protected void toolStripMenuItem最近使ったファイル_Click( object sender, EventArgs e )
1560 // ※このイベントハンドラに対応する「toolStripMenuItem最近使ったファイル」というアイテムはデザイナにはないので注意。
1561 // 「this.t最近使ったファイルをFileメニューへ追加する()」の中で、手動で作って追加したアイテムに対するハンドラである。
1563 this.Act指定されたファイルを開く( ( (ToolStripMenuItem) sender ).Text.Substring( 3 ) );
1567 protected void toolStripMenuItem元に戻す_Click( object sender, EventArgs e )
1571 protected void toolStripMenuItemやり直す_Click( object sender, EventArgs e )
1575 protected void toolStripMenuItem切り取り_Click( object sender, EventArgs e )
1579 protected void toolStripMenuItemコピー_Click( object sender, EventArgs e )
1583 protected void toolStripMenuItem貼り付け_Click( object sender, EventArgs e )
1585 var マウスの位置 = this.現在のマウス位置を譜面パネル内座標pxに変換して返す();
1587 // (A) マウスが譜面上になかった → 表示領域下辺から貼り付ける。
1588 if( ( ( 0 > マウスの位置.X ) || ( 0 > マウスの位置.Y ) ) ||
1589 ( ( マウスの位置.X > this.譜面パネルサイズ.Width ) || ( マウスの位置.Y > this.譜面パネルサイズ.Height ) ) )
1591 this.Act貼り付ける( this.譜面.現在の譜面表示下辺の譜面内絶対位置grid );
1593 // (B) マウスが譜面上にある → そこから貼り付ける。
1596 this.Act貼り付ける( this.譜面.譜面パネル内Y座標pxにおける譜面内絶対位置gridをガイド幅単位で返す( マウスの位置.Y ) );
1599 protected void toolStripMenuItem削除_Click( object sender, EventArgs e )
1603 protected void toolStripMenuItemすべて選択_Click( object sender, EventArgs e )
1607 protected void toolStripMenuItem選択モード_Click( object sender, EventArgs e )
1609 this.選択モードに切替えて関連GUIを設定する();
1611 protected void toolStripMenuItem編集モード_Click( object sender, EventArgs e )
1613 this.編集モードに切替えて関連GUIを設定する();
1615 protected void toolStripMenuItemモード切替え_Click( object sender, EventArgs e )
1619 this.編集モードに切替えて関連GUIを設定する();
1623 this.選択モードに切替えて関連GUIを設定する();
1626 protected void toolStripMenuItem検索_Click( object sender, EventArgs e )
1632 protected void toolStripMenuItemガイド間隔4分_Click( object sender, EventArgs e )
1634 this.Actガイド間隔を変更する( 4 );
1636 protected void toolStripMenuItemガイド間隔6分_Click( object sender, EventArgs e )
1638 this.Actガイド間隔を変更する( 6 );
1640 protected void toolStripMenuItemガイド間隔8分_Click( object sender, EventArgs e )
1642 this.Actガイド間隔を変更する( 8 );
1644 protected void toolStripMenuItemガイド間隔12分_Click( object sender, EventArgs e )
1646 this.Actガイド間隔を変更する( 12 );
1648 protected void toolStripMenuItemガイド間隔16分_Click( object sender, EventArgs e )
1650 this.Actガイド間隔を変更する( 16 );
1652 protected void toolStripMenuItemガイド間隔24分_Click( object sender, EventArgs e )
1654 this.Actガイド間隔を変更する( 24 );
1656 protected void toolStripMenuItemガイド間隔32分_Click( object sender, EventArgs e )
1658 this.Actガイド間隔を変更する( 32 );
1660 protected void toolStripMenuItemガイド間隔48分_Click( object sender, EventArgs e )
1662 this.Actガイド間隔を変更する( 48 );
1664 protected void toolStripMenuItemガイド間隔64分_Click( object sender, EventArgs e )
1666 this.Actガイド間隔を変更する( 64 );
1668 protected void toolStripMenuItemガイド間隔128分_Click( object sender, EventArgs e )
1670 this.Actガイド間隔を変更する( 128 );
1672 protected void toolStripMenuItemガイド間隔フリー_Click( object sender, EventArgs e )
1674 this.Actガイド間隔を変更する( 0 );
1676 protected void toolStripMenuItemガイド間隔拡大_Click( object sender, EventArgs e )
1678 this.Actガイド間隔を拡大する();
1680 protected void toolStripMenuItemガイド間隔縮小_Click( object sender, EventArgs e )
1682 this.Actガイド間隔を縮小する();
1686 protected void toolStripMenuItem先頭から再生_Click( object sender, EventArgs e )
1690 protected void toolStripMenuItem現在位置から再生_Click( object sender, EventArgs e )
1692 this.Act現在位置から再生する();
1694 protected void toolStripMenuItem現在位置からBGMのみ再生_Click( object sender, EventArgs e )
1696 this.Act現在位置からBGMのみ再生する();
1698 protected void toolStripMenuItem再生停止_Click( object sender, EventArgs e )
1704 protected void toolStripMenuItemオプション_Click( object sender, EventArgs e )
1706 this.Actオプションを設定する();
1710 protected void toolStripMenuItemバージョン_Click( object sender, EventArgs e )
1712 this.Actバージョンを表示する();
1718 protected void toolStripButton新規作成_Click( object sender, EventArgs e )
1722 protected void toolStripButton開く_Click( object sender, EventArgs e )
1726 protected void toolStripButton上書き保存_Click( object sender, EventArgs e )
1730 protected void toolStripButton切り取り_Click( object sender, EventArgs e )
1734 protected void toolStripButtonコピー_Click( object sender, EventArgs e )
1738 protected void toolStripButton貼り付け_Click( object sender, EventArgs e )
1740 var マウスの位置 = this.現在のマウス位置を譜面パネル内座標pxに変換して返す();
1742 // (A) マウスが譜面上になかった → 表示領域下辺から貼り付ける。
1743 if( ( ( マウスの位置.X < 0 ) || ( マウスの位置.Y < 0 ) ) ||
1744 ( ( マウスの位置.X > this.譜面パネルサイズ.Width ) || ( マウスの位置.Y > this.譜面パネルサイズ.Height ) ) )
1746 this.Act貼り付ける( this.譜面.現在の譜面表示下辺の譜面内絶対位置grid );
1748 // (B) マウスが譜面上にある → そこから貼り付ける。
1751 this.Act貼り付ける( this.譜面.譜面パネル内Y座標pxにおける譜面内絶対位置gridをガイド幅単位で返す( マウスの位置.Y ) );
1754 protected void toolStripButton削除_Click( object sender, EventArgs e )
1759 protected void toolStripButton元に戻す_Click( object sender, EventArgs e )
1763 protected void toolStripButtonやり直す_Click( object sender, EventArgs e )
1768 protected void toolStripComboBox譜面拡大率_SelectedIndexChanged( object sender, EventArgs e )
1770 this.Act譜面拡大率を変更する( this.toolStripComboBox譜面拡大率.SelectedIndex + 1 );
1772 protected void toolStripComboBoxガイド間隔_SelectedIndexChanged( object sender, EventArgs e )
1774 switch( this.toolStripComboBoxガイド間隔.SelectedIndex )
1777 this.Actガイド間隔を変更する( 4 );
1781 this.Actガイド間隔を変更する( 6 );
1785 this.Actガイド間隔を変更する( 8 );
1789 this.Actガイド間隔を変更する( 12 );
1793 this.Actガイド間隔を変更する( 16 );
1797 this.Actガイド間隔を変更する( 24 );
1801 this.Actガイド間隔を変更する( 32 );
1805 this.Actガイド間隔を変更する( 48 );
1809 this.Actガイド間隔を変更する( 64 );
1813 this.Actガイド間隔を変更する( 128 );
1817 this.Actガイド間隔を変更する( 0 );
1822 protected void toolStripButton選択モード_Click( object sender, EventArgs e )
1826 protected void toolStripButton編集モード_Click( object sender, EventArgs e )
1831 protected void toolStripButton先頭から再生_Click( object sender, EventArgs e )
1835 protected void toolStripButton現在位置から再生_Click( object sender, EventArgs e )
1837 this.Act現在位置から再生する();
1839 protected void toolStripButton現在位置からBGMのみ再生_Click( object sender, EventArgs e )
1841 this.Act現在位置からBGMのみ再生する();
1843 protected void toolStripButton再生停止_Click( object sender, EventArgs e )
1848 protected void toolStripButton音量Down_Click( object sender, EventArgs e )
1850 int 新音量 = this.現在のチップ音量 - 1;
1851 this.現在のチップ音量 = ( 新音量 < メインフォーム.最小音量 ) ? メインフォーム.最小音量 : 新音量;
1853 this.現在のチップ音量をツールバーに表示する();
1855 protected void toolStripButton音量UP_Click( object sender, EventArgs e )
1857 int 新音量 = this.現在のチップ音量 + 1;
1858 this.現在のチップ音量 = ( 新音量 > メインフォーム.最大音量 ) ? メインフォーム.最大音量 : 新音量;
1860 this.現在のチップ音量をツールバーに表示する();
1864 #region " 分割パネルコンテナ、譜面パネル、スクロールバー "
1866 protected void pictureBox譜面パネル_MouseClick( object sender, MouseEventArgs e )
1869 this.pictureBox譜面パネル.Focus();
1871 // 選択・編集モードオブジェクトのいずれかへ処理を引き継ぐ。
1874 this.選択モード.MouseClick( e );
1878 this.編集モード.MouseClick( e );
1881 protected void pictureBox譜面パネル_MouseDown( object sender, MouseEventArgs e )
1883 // 選択モードオブジェクトへ処理を引き継ぐ。
1885 this.選択モード.MouseDown( e );
1887 protected void pictureBox譜面パネル_MouseEnter( object sender, EventArgs e )
1889 // オートフォーカスが有効の場合、譜面にマウスが入ったら譜面がフォーカスを得る。"
1890 if( this.Config.AutoFocus )
1891 this.pictureBox譜面パネル.Focus();
1893 protected void pictureBox譜面パネル_MouseLeave( object sender, EventArgs e )
1895 // 編集モードオブジェクトへ処理を引き継ぐ。
1897 this.編集モード.MouseLeave( e );
1899 protected void pictureBox譜面パネル_MouseMove( object sender, MouseEventArgs e )
1901 // 選択・編集モードオブジェクトのいずれかへ処理を引き継ぐ。
1904 this.選択モード.MouseMove( e );
1908 this.編集モード.MouseMove( e );
1911 protected void pictureBox譜面パネル_Paint( object sender, PaintEventArgs e )
1913 if( false == this.初期化完了 )
1914 return; // 初期化が終わってないのに呼び出されることがあるので、その場合は無視。
1916 #region " 小節数が変わってたら、スクロールバーの値域を調整する。"
1918 int 全譜面の高さgrid = this.譜面.全小節の高さgrid;
1920 if( this.vScrollBar譜面用垂直スクロールバー.Maximum != 全譜面の高さgrid - 1 ) // 小節数が変わっている
1922 // 譜面の高さ(grid)がどれだけ変わったか?
1923 int 増加分grid = ( 全譜面の高さgrid - 1 ) - this.vScrollBar譜面用垂直スクロールバー.Maximum;
1925 #region " スクロールバーの状態を新しい譜面の高さに合わせる。"
1928 int value = this.vScrollBar譜面用垂直スクロールバー.Value; // 次の式で Maximum が Value より小さくなると例外が発生するので、
1929 this.vScrollBar譜面用垂直スクロールバー.Value = 0; // Value のバックアップを取っておいて、ひとまず 0 にする。
1930 this.vScrollBar譜面用垂直スクロールバー.Maximum = 全譜面の高さgrid - 1;
1932 int newValue = value + 増加分grid;
1934 // オーバーフローしないようクリッピングする。
1937 this.vScrollBar譜面用垂直スクロールバー.Value = 0;
1939 else if( ( this.vScrollBar譜面用垂直スクロールバー.Maximum - this.vScrollBar譜面用垂直スクロールバー.LargeChange ) <= newValue )
1941 this.vScrollBar譜面用垂直スクロールバー.Value = this.vScrollBar譜面用垂直スクロールバー.Maximum - this.vScrollBar譜面用垂直スクロールバー.LargeChange;
1945 this.vScrollBar譜面用垂直スクロールバー.Value = newValue;
1950 #region " 譜面表示下辺の位置を更新する。"
1952 this.譜面.現在の譜面表示下辺の譜面内絶対位置grid =
1953 ( ( this.vScrollBar譜面用垂直スクロールバー.Maximum - this.vScrollBar譜面用垂直スクロールバー.LargeChange ) + 1 ) - this.vScrollBar譜面用垂直スクロールバー.Value;
1961 this.譜面.描画する( e.Graphics, this.pictureBox譜面パネル );
1965 // 選択・編集モードオブジェクトのいずれかへ処理を引き継ぐ。
1968 this.選択モード.Paint( e );
1972 this.編集モード.Paint( e );
1975 protected void pictureBox譜面パネル_PreviewKeyDown( object sender, PreviewKeyDownEventArgs e )
1977 if( Keys.Prior == e.KeyCode )
1979 #region " PageUp → 移動量に対応する grid だけ垂直つまみを移動させる。あとはこの移動で生じる ChangedValue イベントで処理。"
1981 int 移動すべき数grid = -this.GRID_PER_PART;
1982 int 新しい位置 = this.vScrollBar譜面用垂直スクロールバー.Value + 移動すべき数grid;
1983 int 最小値 = this.vScrollBar譜面用垂直スクロールバー.Minimum;
1984 int 最大値 = ( this.vScrollBar譜面用垂直スクロールバー.Maximum + 1 ) - this.vScrollBar譜面用垂直スクロールバー.LargeChange;
1990 else if( 新しい位置 > 最大値 )
1994 this.vScrollBar譜面用垂直スクロールバー.Value = 新しい位置;
1998 else if( Keys.Next == e.KeyCode )
2000 #region " PageDown → 移動量に対応する grid だけ垂直つまみを移動させる。あとはこの移動で生じる ChangedValue イベントで処理。"
2002 int 移動すべき数grid = this.GRID_PER_PART;
2003 int 新しい位置 = this.vScrollBar譜面用垂直スクロールバー.Value + 移動すべき数grid;
2004 int 最小値 = this.vScrollBar譜面用垂直スクロールバー.Minimum;
2005 int 最大値 = ( this.vScrollBar譜面用垂直スクロールバー.Maximum + 1 ) - this.vScrollBar譜面用垂直スクロールバー.LargeChange;
2011 else if( 新しい位置 > 最大値 )
2015 this.vScrollBar譜面用垂直スクロールバー.Value = 新しい位置;
2021 // 編集モードオブジェクトへ処理を引き継ぐ。
2023 this.編集モード.PreviewKeyDown( e );
2027 protected void splitContainer分割パネルコンテナ_MouseWheel( object sender, MouseEventArgs e )
2029 if( false == this.初期化完了 )
2030 return; // 初期化が終わってないのに呼び出されることがあるので、その場合は無視。
2032 #region " 移動量に対応する grid だけ垂直つまみを移動させる。あとはこの移動で生じる ChangedValue イベントで処理する。"
2037 // e.Delta は、スクロールバーを下へ動かしたいときに負、上へ動かしたいときに正となる。
2038 int 移動すべき行数 = ( -e.Delta * SystemInformation.MouseWheelScrollLines ) / 120;
2041 int 移動すべき数grid = 移動すべき行数 * ( this.GRID_PER_PART / 4 );
2043 // スクロールバーのつまみを移動する。
2044 int 新しい位置 = this.vScrollBar譜面用垂直スクロールバー.Value + 移動すべき数grid;
2045 int 最小値 = this.vScrollBar譜面用垂直スクロールバー.Minimum;
2046 int 最大値 = ( this.vScrollBar譜面用垂直スクロールバー.Maximum + 1 ) - this.vScrollBar譜面用垂直スクロールバー.LargeChange;
2052 else if( 新しい位置 > 最大値 )
2056 this.vScrollBar譜面用垂直スクロールバー.Value = 新しい位置;
2060 protected void splitContainer分割パネルコンテナ_Panel2_SizeChanged( object sender, EventArgs e )
2062 if( false == this.初期化完了 )
2063 return; // 初期化が終わってないのに呼び出されることがあるので、その場合は無視。
2065 this.垂直スクロールバーと譜面の上下位置を調整する();
2067 protected void splitContainer分割パネルコンテナ_Panel2_Paint( object sender, PaintEventArgs e )
2069 if( false == this.初期化完了 )
2070 return; // 初期化が終わってないのに呼び出されることがあるので、その場合は無視。
2073 var メモ領域左上隅の位置 = new PointF() {
2074 X = this.譜面.レーンの合計幅px,
2075 Y = this.pictureBox譜面パネル.Location.Y,
2078 #region " 見出し<小節メモ>を描画する。"
2080 g.DrawString( Properties.Resources.MSG_小節メモ, this.メモ用フォント, Brushes.White, PointF.Add( メモ領域左上隅の位置, new Size( 24, -24 )/*マージン*/ ) );
2083 #region " 小節メモを描画する。"
2086 // グリッド値は 上辺>下辺 なので注意。
2087 int パネル下辺grid = this.譜面.現在の譜面表示下辺の譜面内絶対位置grid;
2088 int パネル上辺grid = パネル下辺grid + ( this.pictureBox譜面パネル.ClientSize.Height * this.GRID_PER_PIXEL );
2089 int 開始小節番号 = this.譜面.現在譜面表示下辺に存在している小節番号;
2091 for( int 小節番号 = 開始小節番号; 小節番号 <= this.譜面.SSTFormatScore.最大小節番号; 小節番号++ )
2093 int 小節の下辺grid = this.譜面.小節先頭の譜面内絶対位置gridを返す( 小節番号 );
2094 int 小節の上辺grid = 小節の下辺grid + this.譜面.小節長をグリッドで返す( 小節番号 );
2096 if( 小節の下辺grid > パネル上辺grid )
2097 break; // 小節が画面上方にはみ出し切ってしまったらそこで終了。
2099 if( this.譜面.SSTFormatScore.dicメモ.ContainsKey( 小節番号 ) )
2101 string メモ = this.譜面.SSTFormatScore.dicメモ[ 小節番号 ];
2103 string[] lines = メモ.Split( new string[] { Environment.NewLine }, StringSplitOptions.None );
2104 int 行数 = lines.Length;
2106 var メモの位置 = new PointF() {
2107 X = メモ領域左上隅の位置.X + 4, // + 4 はマージン
2108 Y = メモ領域左上隅の位置.Y + ( パネル上辺grid - 小節の下辺grid ) / this.GRID_PER_PIXEL - ( 行数 * 16 ), // 9pt = だいたい16px
2110 g.DrawString( メモ, this.メモ用フォント, Brushes.White, メモの位置 );
2117 protected void vScrollBar譜面用垂直スクロールバー_ValueChanged( object sender, EventArgs e )
2119 if( false == this.初期化完了 )
2120 return; // 初期化が終わってないのに呼び出されることがあるので、その場合は無視。
2122 var bar = vScrollBar譜面用垂直スクロールバー;
2127 this.譜面.現在の譜面表示下辺の譜面内絶対位置grid = ( ( bar.Maximum + 1 ) - bar.LargeChange ) - bar.Value;
2129 // 編集モードの場合、カーソルのgrid位置を再計算。
2132 this.編集モード.MouseMove(
2133 new MouseEventArgs( MouseButtons.None, 0, this.編集モード.現在のチップカーソル領域.X, this.編集モード.現在のチップカーソル領域.Y, 0 ) );
2137 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2138 this.numericUpDownメモ用小節番号.Value = this.譜面.現在カレントラインに存在している小節番号;
2139 this.次のプロパティ変更がUndoRedoリストに載るようにする();
2142 this.splitContainer分割パネルコンテナ.Panel2.Refresh();
2149 protected void toolStripMenuItem選択チップの切り取り_Click( object sender, EventArgs e )
2153 protected void toolStripMenuItem選択チップのコピー_Click( object sender, EventArgs e )
2157 protected void toolStripMenuItem選択チップの貼り付け_Click( object sender, EventArgs e )
2159 // メニューが開かれたときのマウスの座標を取得。
2160 // ※メニューは必ずマウス位置を左上にして表示されるとは限らないため、メニューの表示位置からは取得しないこと。
2161 var マウスの位置 = this.選択モードのコンテクストメニューを開いたときのマウスの位置;
2163 if( this.譜面.譜面パネル内X座標pxにある編集レーンを返す( マウスの位置.X ) == 編集レーン種別.Unknown )
2164 return; // クリックされた場所にレーンがないなら無視。
2167 this.Act貼り付ける( this.譜面.譜面パネル内Y座標pxにおける譜面内絶対位置gridをガイド幅単位で返す( マウスの位置.Y ) );
2169 protected void toolStripMenuItem選択チップの削除_Click( object sender, EventArgs e )
2173 protected void toolStripMenuItemすべてのチップの選択_Click( object sender, EventArgs e )
2175 // 編集モードなら強制的に選択モードにする。
2177 this.選択モードに切替えて関連GUIを設定する();
2180 this.選択モード.全チップを選択する();
2182 protected void toolStripMenuItem小節長変更_Click( object sender, EventArgs e )
2184 // メニューが開かれたときのマウスの座標を取得。
2185 // ※メニューは必ずマウス位置を左上にして表示されるとは限らないため、メニューの表示位置からは取得しないこと。
2186 var マウスの位置 = this.選択モードのコンテクストメニューを開いたときのマウスの位置;
2188 if( this.譜面.譜面パネル内X座標pxにある編集レーンを返す( マウスの位置.X ) == 編集レーン種別.Unknown )
2189 return; // クリックされた場所にレーンがないなら無視。
2192 this.Act小節長倍率を変更する( this.譜面.譜面パネル内Y座標pxにおける小節番号を返す( マウスの位置.Y ) );
2194 protected void toolStripMenuItem小節の挿入_Click( object sender, EventArgs e )
2196 // メニューが開かれたときのマウスの座標を取得。
2197 // ※メニューは必ずマウス位置を左上にして表示されるとは限らないため、メニューの表示位置からは取得しないこと。
2198 var マウスの位置 = this.選択モードのコンテクストメニューを開いたときのマウスの位置;
2200 if( this.譜面.譜面パネル内X座標pxにある編集レーンを返す( マウスの位置.X ) == 編集レーン種別.Unknown )
2201 return; // クリックされた場所にレーンがないなら無視。
2204 this.Act小節を挿入する( this.譜面.譜面パネル内Y座標pxにおける小節番号を返す( マウスの位置.Y ) );
2206 protected void toolStripMenuItem小節の削除_Click( object sender, EventArgs e )
2208 // メニューが開かれたときのマウスの座標を取得。
2209 // ※メニューは必ずマウス位置を左上にして表示されるとは限らないため、メニューの表示位置からは取得しないこと。
2210 var マウスの位置 = this.選択モードのコンテクストメニューを開いたときのマウスの位置;
2212 if( this.譜面.譜面パネル内X座標pxにある編集レーンを返す( マウスの位置.X ) == 編集レーン種別.Unknown )
2213 return; // クリックされた場所にレーンがないなら無視。
2216 this.Act小節を削除する( this.譜面.譜面パネル内Y座標pxにおける小節番号を返す( マウスの位置.Y ) );
2222 protected void textBox曲名_TextChanged( object sender, EventArgs e )
2224 #region " この変更が Undo/Redo したことによるものではない場合、UndoRedoセルを追加 or 修正する。"
2226 if( false == UndoRedo.管理.UndoRedoした直後である )
2229 var cell = this.UndoRedo管理.Undoするセルを取得して返す_見るだけ();
2231 if( ( null != cell ) && cell.所有権がある( this.textBox曲名 ) )
2233 // (A) 所有者である → 最新のセルの "変更後の値" を現在のコントロールの値に更新する。
2234 ( (UndoRedo.セル<string>) cell ).変更後の値 = this.textBox曲名.Text;
2238 // (B) 所有者ではない → 以下のようにセルを新規追加する。
2241 // "所有者ID" ← 対象となるコンポーネントオブジェクト
2242 var cc = new UndoRedo.セル<string>(
2243 所有者ID: this.textBox曲名,
2244 Undoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
2245 this.タブを選択する( タブ種別.基本情報 );
2246 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2247 this.textBox曲名.Text = 変更前;
2248 this.textBox曲名.Focus();
2250 Redoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
2251 this.タブを選択する( タブ種別.基本情報 );
2252 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2253 this.textBox曲名.Text = 変更後;
2254 this.textBox曲名.Focus();
2257 変更前の値: this.textBox曲名_以前の値,
2258 変更後の値: this.textBox曲名.Text,
2262 this.UndoRedo管理.セルを追加する( cc );
2265 this.UndoRedo用GUIのEnabledを設定する();
2271 this.textBox曲名_以前の値 = this.textBox曲名.Text; // 以前の値 ← 現在の値
2272 UndoRedo.管理.UndoRedoした直後である = false;
2276 譜面.SSTFormatScore.Header.曲名 = this.textBox曲名.Text;
2278 protected void textBox曲名_Leave( object sender, EventArgs e )
2280 // 最新の UndoRedoセル の所有権を放棄する。
2281 this.UndoRedo管理.Undoするセルを取得して返す_見るだけ()?.所有権を放棄する( this.textBox曲名 );
2283 protected string textBox曲名_以前の値 = "";
2285 protected void textBox説明_TextChanged( object sender, EventArgs e )
2287 #region " この変更が Undo/Redo したことによるものではない場合、UndoRedoセルを追加 or 修正する。"
2289 if( false == UndoRedo.管理.UndoRedoした直後である )
2292 var cell = this.UndoRedo管理.Undoするセルを取得して返す_見るだけ();
2293 if( ( null != cell ) && cell.所有権がある( this.textBox説明 ) )
2295 // (A) 所有者である → 最新のセルの "変更後の値" を現在のコントロールの値に更新。
2297 ( (UndoRedo.セル<string>) cell ).変更後の値 = this.textBox説明.Text;
2301 // (B) 所有者ではない → 以下のようにセルを新規追加する。
2304 // "所有者ID" ← 対象となるコンポーネントオブジェクト
2305 var cc = new UndoRedo.セル<string>(
2306 所有者ID: this.textBox説明,
2307 Undoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
2308 this.タブを選択する( タブ種別.基本情報 );
2309 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2310 this.textBox説明.Text = 変更前;
2311 this.textBox説明.Focus();
2313 Redoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
2314 this.タブを選択する( タブ種別.基本情報 );
2315 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2316 this.textBox説明.Text = 変更後;
2317 this.textBox説明.Focus();
2320 変更前の値: this.textBox説明_以前の値,
2321 変更後の値: this.textBox説明.Text,
2325 this.UndoRedo管理.セルを追加する( cc );
2328 this.UndoRedo用GUIのEnabledを設定する();
2334 this.textBox説明_以前の値 = this.textBox説明.Text; // 以前の値 ← 現在の値
2335 UndoRedo.管理.UndoRedoした直後である = false;
2339 譜面.SSTFormatScore.Header.説明文 = this.textBox説明.Text;
2341 protected void textBox説明_Leave( object sender, EventArgs e )
2343 // 最新 UndoRedoセル の所有権を放棄する。
2344 this.UndoRedo管理.Undoするセルを取得して返す_見るだけ()?.所有権を放棄する( this.textBox説明 );
2346 protected string textBox説明_以前の値 = "";
2348 protected void textBoxメモ_TextChanged( object sender, EventArgs e )
2350 #region " この変更が Undo/Redo したことによるものではない場合、UndoRedoセルを追加or修正する。"
2352 if( !UndoRedo.管理.UndoRedoした直後である )
2356 UndoRedo.セルBase cell = this.UndoRedo管理.Undoするセルを取得して返す_見るだけ();
2358 if( ( cell != null ) && cell.所有権がある( this.textBoxメモ ) )
2360 // (Yes) 最新のセルの "変更後の値" を <現在の値> に更新。
2362 ( (UndoRedo.セル<string>) cell ).変更後の値 = this.textBoxメモ.Text;
2369 // "所有者ID" = 対象となるコンポーネントオブジェクト
2371 var cc = new UndoRedo.セル<string>(
2372 所有者ID: this.textBoxメモ,
2373 Undoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
2374 this.タブを選択する( タブ種別.基本情報 );
2375 this.numericUpDownメモ用小節番号.Value = (decimal) 任意1;
2376 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2377 this.textBoxメモ.Text = 変更前;
2378 this.textBoxメモ.Focus();
2380 int 小節番号 = (int) ( (decimal) 任意1 );
2382 #region " dicメモ の更新 "
2384 if( this.譜面.SSTFormatScore.dicメモ.ContainsKey( 小節番号 ) )
2386 if( string.IsNullOrEmpty( 変更前 ) )
2387 this.譜面.SSTFormatScore.dicメモ.Remove( 小節番号 );
2389 this.譜面.SSTFormatScore.dicメモ[ 小節番号 ] = 変更前;
2393 if( !string.IsNullOrEmpty( 変更前 ) )
2394 this.譜面.SSTFormatScore.dicメモ.Add( 小節番号, 変更前 );
2399 this.Act小節の先頭へ移動する( 小節番号 );
2400 this.splitContainer分割パネルコンテナ.Panel2.Refresh(); // 小節メモをリフレッシュ。
2402 Redoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
2403 this.タブを選択する( タブ種別.基本情報 );
2404 this.numericUpDownメモ用小節番号.Value = (decimal) 任意1;
2405 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2406 this.textBoxメモ.Text = 変更後;
2407 this.textBoxメモ.Focus();
2409 int 小節番号 = (int) ( (decimal) 任意1 );
2411 #region " dicメモの更新 "
2413 if( this.譜面.SSTFormatScore.dicメモ.ContainsKey( 小節番号 ) )
2415 if( string.IsNullOrEmpty( 変更後 ) )
2416 this.譜面.SSTFormatScore.dicメモ.Remove( 小節番号 );
2418 this.譜面.SSTFormatScore.dicメモ[ 小節番号 ] = 変更後;
2422 if( !string.IsNullOrEmpty( 変更後 ) )
2423 this.譜面.SSTFormatScore.dicメモ.Add( 小節番号, 変更後 );
2428 this.Act小節の先頭へ移動する( 小節番号 );
2429 this.splitContainer分割パネルコンテナ.Panel2.Refresh(); // 小節メモをリフレッシュ。
2432 変更前の値: this.textBoxメモ_以前の値,
2433 変更後の値: this.textBoxメモ.Text,
2434 任意1: (object) this.numericUpDownメモ用小節番号.Value,
2437 this.UndoRedo管理.セルを追加する( cc );
2440 this.UndoRedo用GUIのEnabledを設定する();
2446 this.textBoxメモ_以前の値 = this.textBoxメモ.Text; // <以前の値> = <現在の値>
2448 if( false == UndoRedo.管理.UndoRedoした直後である )
2451 UndoRedo.管理.UndoRedoした直後である = false;
2453 #region " 小節番号に対応するメモを dicメモ に登録する。"
2456 int 小節番号 = (int) this.numericUpDownメモ用小節番号.Value;
2458 if( string.IsNullOrEmpty( this.textBoxメモ.Text ) )
2461 if( this.譜面.SSTFormatScore.dicメモ.ContainsKey( 小節番号 ) )
2462 this.譜面.SSTFormatScore.dicメモ.Remove( 小節番号 ); // 存在してたら削除。
2468 if( this.譜面.SSTFormatScore.dicメモ.ContainsKey( 小節番号 ) )
2469 this.譜面.SSTFormatScore.dicメモ[ 小節番号 ] = this.textBoxメモ.Text; // 存在してたら更新。
2471 this.譜面.SSTFormatScore.dicメモ.Add( 小節番号, this.textBoxメモ.Text ); // 存在してなかったら追加。
2476 #region " もし最終小節だったなら、後ろに4つ小節を加える。"
2479 int 小節番号 = (int) this.numericUpDownメモ用小節番号.Value;
2480 if( 小節番号 == this.譜面.SSTFormatScore.最大小節番号 )
2482 this.譜面.最後の小節の後ろに小節を4つ追加する();
2488 protected void textBoxメモ_Leave( object sender, EventArgs e )
2490 // 最新 UndoRedoセル の所有権を放棄する。
2491 this.UndoRedo管理.Undoするセルを取得して返す_見るだけ()?.所有権を放棄する( this.textBoxメモ );
2494 this.splitContainer分割パネルコンテナ.Panel2.Refresh();
2496 protected string textBoxメモ_以前の値 = "";
2498 protected void numericUpDownメモ用小節番号_ValueChanged( object sender, EventArgs e )
2500 // 小節番号にあわせて、textBoxメモにメモを表示する。
2501 int 小節番号 = (int) this.numericUpDownメモ用小節番号.Value;
2502 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2503 if( this.譜面.SSTFormatScore.dicメモ.ContainsKey( 小節番号 ) )
2504 this.textBoxメモ.Text = this.譜面.SSTFormatScore.dicメモ[ 小節番号 ];
2506 this.textBoxメモ.Text = "";
2507 this.次のプロパティ変更がUndoRedoリストに載るようにする();
2512 private Font メモ用フォント = new Font( FontFamily.GenericSansSerif, 9.0f );
2513 private readonly Dictionary<int, string> dic音量ラベル = new Dictionary<int, string>() {
2514 { 1, "1 (Smallest)" },
2515 { 2, "2 (Smaller)" },
2516 { 3, "3 (Middle)" },
2517 { 4, "4 (Normal)" },