2 using System.Collections.Generic;
3 using System.Diagnostics;
7 using System.Reflection;
8 using System.Windows.Forms;
12 // ※デザイナでは開けないので注意すること。
14 partial class メインフォーム : Form
16 public int メジャーバージョン番号 => ( Assembly.GetExecutingAssembly().GetName().Version.Major );
17 public int マイナーバージョン番号 => ( Assembly.GetExecutingAssembly().GetName().Version.Minor );
18 public int リビジョン番号 => ( Assembly.GetExecutingAssembly().GetName().Version.Revision );
19 public int ビルド番号 => ( Assembly.GetExecutingAssembly().GetName().Version.Build );
21 public const int 最大音量 = 4;
22 public const int 最小音量 = 1;
28 return this.bs_未保存である;
33 this.bs_未保存である = value;
35 // ウィンドウのタイトルバーの文字列を修正する。
36 string 表示するファイルの名前 = ( string.IsNullOrEmpty( this.編集中のファイル名 ) ) ? Properties.Resources.NEW_FILENAME : this.編集中のファイル名;
39 // 変更ありかつ未保存なら「*」を付ける。
40 this.Text = $"SSTFEditor {this.メジャーバージョン番号}.{this.マイナーバージョン番号}.{this.リビジョン番号}.{this.ビルド番号} *[{表示するファイルの名前}]";
41 this.toolStripMenuItem上書き保存.Enabled = true;
42 this.toolStripButton上書き保存.Enabled = true;
46 // 保存後変更がないなら「*」は付けない。
47 this.Text = $"SSTFEditor {this.メジャーバージョン番号}.{this.マイナーバージョン番号}.{this.リビジョン番号}.{this.ビルド番号} [{表示するファイルの名前}]";
48 this.toolStripMenuItem上書き保存.Enabled = false;
49 this.toolStripButton上書き保存.Enabled = false;
53 public bool 選択モードである => ( ( CheckState.Checked == this.toolStripButton選択モード.CheckState ) ? true : false );
54 public bool 編集モードである => ( ( CheckState.Checked == this.toolStripButton編集モード.CheckState ) ? true : false );
56 public int GRID_PER_PART { get; protected set; }
57 public int GRID_PER_PIXEL => ( this.bs_GRID_PER_PIXEL / ( this.toolStripComboBox譜面拡大率.SelectedIndex + 1 ) );
59 public bool 初期化完了 = false;
64 public UndoRedo.管理 UndoRedo管理;
65 public クリップボード クリップボード;
66 public Size 譜面パネルサイズ => ( this.pictureBox譜面パネル.ClientSize );
67 public SSTFormat.チップ種別 現在のチップ種別
71 return this.bs_e現在のチップ種別;
75 this.bs_e現在のチップ種別 = value;
76 this.label現在のチップ種別.Text = this.チップ種別toチップ名対応表[ value ];
79 public int 現在のチップ音量 = メインフォーム.最大音量;
83 InitializeComponent();
88 public void 選択モードに切替えて関連GUIを設定する()
90 this.toolStripButton選択モード.CheckState = CheckState.Checked;
91 this.toolStripButton編集モード.CheckState = CheckState.Unchecked;
93 this.toolStripMenuItem選択モード.CheckState = CheckState.Checked;
94 this.toolStripMenuItem編集モード.CheckState = CheckState.Unchecked;
96 this.label現在のチップ種別.Text = "----";
100 public void 編集モードに切替えて関連GUIを設定する()
102 this.選択モード.全チップの選択を解除する();
105 this.toolStripButton選択モード.CheckState = CheckState.Unchecked;
106 this.toolStripButton編集モード.CheckState = CheckState.Checked;
108 this.toolStripMenuItem選択モード.CheckState = CheckState.Unchecked;
109 this.toolStripMenuItem編集モード.CheckState = CheckState.Checked;
111 public void 選択チップの有無に応じて編集用GUIのEnabledを設定する()
113 bool 譜面上に選択チップがある = this.選択チップが1個以上ある;
114 bool クリップボードに選択チップがある = ( null != this.クリップボード ) && ( 0 < this.クリップボード.セル数 );
116 // 編集メニューの Enabled 設定
117 this.toolStripMenuItemコピー.Enabled = 譜面上に選択チップがある;
118 this.toolStripMenuItem切り取り.Enabled = 譜面上に選択チップがある;
119 this.toolStripMenuItem貼り付け.Enabled = クリップボードに選択チップがある;
120 this.toolStripMenuItem削除.Enabled = 譜面上に選択チップがある;
123 this.toolStripButtonコピー.Enabled = 譜面上に選択チップがある;
124 this.toolStripButton切り取り.Enabled = 譜面上に選択チップがある;
125 this.toolStripButton貼り付け.Enabled = クリップボードに選択チップがある;
126 this.toolStripButton削除.Enabled = 譜面上に選択チップがある;
129 this.toolStripMenuItem選択チップのコピー.Enabled = 譜面上に選択チップがある;
130 this.toolStripMenuItem選択チップの切り取り.Enabled = 譜面上に選択チップがある;
131 this.toolStripMenuItem選択チップの貼り付け.Enabled = クリップボードに選択チップがある;
132 this.toolStripMenuItem選択チップの削除.Enabled = 譜面上に選択チップがある;
134 public void 譜面をリフレッシュする()
136 this.pictureBox譜面パネル.Refresh();
138 public void UndoRedo用GUIのEnabledを設定する()
140 bool Undo可 = ( 0 < this.UndoRedo管理.Undo可能な回数 ) ? true : false;
141 bool Redo可 = ( 0 < this.UndoRedo管理.Redo可能な回数 ) ? true : false;
143 this.toolStripMenuItem元に戻す.Enabled = Undo可;
144 this.toolStripMenuItemやり直す.Enabled = Redo可;
145 this.toolStripButton元に戻す.Enabled = Undo可;
146 this.toolStripButtonやり直す.Enabled = Redo可;
148 public void 選択モードのコンテクストメニューを表示する( int x, int y )
150 this.contextMenuStrip譜面右メニュー.Show( this.pictureBox譜面パネル, x, y );
152 // メニューを表示した時のマウス座標を控えておく。
153 this.選択モードのコンテクストメニューを開いたときのマウスの位置 = new Point( x, y );
155 public void 譜面を縦スクロールする( int nスクロール量grid )
157 int 現在の位置grid = this.vScrollBar譜面用垂直スクロールバー.Value;
158 int スクロール後の位置grid = this.vScrollBar譜面用垂直スクロールバー.Value + nスクロール量grid;
159 int 最小値grid = this.vScrollBar譜面用垂直スクロールバー.Minimum;
160 int 最大値grid = ( this.vScrollBar譜面用垂直スクロールバー.Maximum + 1 ) - this.vScrollBar譜面用垂直スクロールバー.LargeChange;
162 if( スクロール後の位置grid < 最小値grid )
164 スクロール後の位置grid = 最小値grid;
166 else if( スクロール後の位置grid > 最大値grid )
168 スクロール後の位置grid = 最大値grid;
171 this.vScrollBar譜面用垂直スクロールバー.Value = スクロール後の位置grid;
174 protected readonly Dictionary<SSTFormat.チップ種別, string> チップ種別toチップ名対応表 = new Dictionary<SSTFormat.チップ種別, string>() {
177 { SSTFormat.チップ種別.Bass, "BassDrum" },
178 { SSTFormat.チップ種別.BPM, "BPM" },
179 { SSTFormat.チップ種別.China, "China" },
180 { SSTFormat.チップ種別.HiHat_Close, "HiHat(Close)" },
181 { SSTFormat.チップ種別.HiHat_Foot, "FootPedal" },
182 { SSTFormat.チップ種別.HiHat_HalfOpen, "HiHat(HarfOpen)" },
183 { SSTFormat.チップ種別.HiHat_Open, "HiHat(Open)" },
184 { SSTFormat.チップ種別.LeftCrash, "Crash" },
185 { SSTFormat.チップ種別.Ride, "Ride" },
186 { SSTFormat.チップ種別.Ride_Cup, "Ride(Cup)" },
187 { SSTFormat.チップ種別.RightCrash, "Crash" },
188 { SSTFormat.チップ種別.Snare, "Snare" },
189 { SSTFormat.チップ種別.Snare_ClosedRim, "Snare(CloseRimShot)" },
190 { SSTFormat.チップ種別.Snare_Ghost, "Snare(Ghost)" },
191 { SSTFormat.チップ種別.Snare_OpenRim, "Snare(OpenRimShot)" },
192 { SSTFormat.チップ種別.Splash, "Splash" },
193 { SSTFormat.チップ種別.Tom1, "HighTom" },
194 { SSTFormat.チップ種別.Tom1_Rim, "HighTom(RimShot)" },
195 { SSTFormat.チップ種別.Tom2, "LowTom" },
196 { SSTFormat.チップ種別.Tom2_Rim, "LowTom(RimShot)" },
197 { SSTFormat.チップ種別.Tom3, "FloorTom" },
198 { SSTFormat.チップ種別.Tom3_Rim, "FloorTom(RimShot)" },
199 { SSTFormat.チップ種別.Unknown, "" },
200 { SSTFormat.チップ種別.小節線, "" },
201 { SSTFormat.チップ種別.背景動画, "" },
202 { SSTFormat.チップ種別.拍線, "" },
203 { SSTFormat.チップ種別.小節メモ, "" },
207 protected bool 選択チップが1個以上ある
211 if( ( null != this.譜面.SSTFormatScore ) &&
212 ( null != this.譜面.SSTFormatScore.チップリスト ) &&
213 ( 0 < this.譜面.SSTFormatScore.チップリスト.Count ) )
215 foreach( var chip in this.譜面.SSTFormatScore.チップリスト )
224 protected int 現在のガイド間隔 = 0;
225 protected Point 選択モードのコンテクストメニューを開いたときのマウスの位置;
227 private bool bs_未保存である = false;
228 private SSTFormat.チップ種別 bs_e現在のチップ種別;
229 private int bs_GRID_PER_PIXEL = 1;
232 /// SSTFEditor.exe と StrokeStyleT.exe が格納されているフォルダへのパス。
234 protected string システムフォルダパス => ( Path.GetDirectoryName( Application.ExecutablePath ) );
236 /// Windowsログインユーザのアプリデータフォルダ。
240 /// 例: "C:\Users\ログインユーザ名\ApplicationData\SSTFEditor\"
242 protected string ユーザフォルダパス
246 var path = Path.Combine( Environment.GetFolderPath( Environment.SpecialFolder.ApplicationData, Environment.SpecialFolderOption.Create ), @"SSTFEditor\" );
248 if( false == Directory.Exists( path ) )
249 Directory.CreateDirectory( path ); // なければ作成する。
254 protected string 作業フォルダパス = null;
255 protected string 編集中のファイル名 = null;
256 protected string Viewerの絶対パスファイル名 = null;
257 protected string 最後にプレイヤーに渡した一時ファイル名 = null;
259 // アクションメソッド(機能ツリーの最上位。メニューやコマンドバーなどから呼び出される。)
261 protected void Actアプリを起動する()
263 this.GRID_PER_PART = int.Parse( Properties.Resources.GRID_PER_PART );
264 this.bs_GRID_PER_PIXEL = int.Parse( Properties.Resources.GRID_PER_PIXEL );
266 // 作業フォルダの初期値は、Windowsユーザのマイドキュメントフォルダ。
267 this.作業フォルダパス = Environment.GetFolderPath( Environment.SpecialFolder.MyDocuments );
269 // プレイヤーは、exe と同じ場所にあるものとする。
270 this.Viewerの絶対パスファイル名 = Path.Combine( this.システムフォルダパス, Properties.Resources.PLAYER_NAME );
273 this.Config = Config.読み込む( Path.Combine( this.ユーザフォルダパス, Properties.Resources.CONFIG_FILE_NAME ) );
275 // デザイナでは追加できないイベントを手動で追加する。
276 this.splitContainer分割パネルコンテナ.MouseWheel += new MouseEventHandler( splitContainer分割パネルコンテナ_MouseWheel );
279 this.ConfigのRecentUsedFilesをファイルメニューへ追加する();
283 this.Actガイド間隔を変更する( 16 ); // 初期は 1/16 間隔。
284 this.Act譜面拡大率を変更する( 1 ); // 初期は 標準。
289 protected void Actアプリを終了する()
291 // 一時ファイルが残っていれば、削除する。
292 if( File.Exists( this.最後にプレイヤーに渡した一時ファイル名 ) )
293 File.Delete( this.最後にプレイヤーに渡した一時ファイル名 );
296 this.Config.保存する( Path.Combine( this.ユーザフォルダパス, Properties.Resources.CONFIG_FILE_NAME ) );
298 FDK.Utilities.解放する( ref this.譜面 );
299 FDK.Utilities.解放する( ref this.選択モード );
301 protected void Act新規作成する()
303 if( DialogResult.Cancel == this.未保存なら保存する() )
304 return; // 保存がキャンセルされた場合はここで中断。
308 protected void Act開く()
310 if( DialogResult.Cancel == this.未保存なら保存する() )
311 return; // 保存がキャンセルされた場合はここで中断。
313 #region " [ファイルを開く] ダイアログでファイルを選択する。"
315 var dialog = new OpenFileDialog() {
316 Title = Properties.Resources.MSG_ファイル選択ダイアログのタイトル,
317 Filter = Properties.Resources.MSG_ファイル選択ダイアログのフィルタ,
319 InitialDirectory = this.作業フォルダパス,
321 var result = dialog.ShowDialog( this );
323 // メインフォームを再描画してダイアログを完全に消す。
327 if( DialogResult.OK != result )
332 this.ファイルを読み込む( dialog.FileName );
334 protected void Act指定されたファイルを開く( string ファイルパス )
336 if( DialogResult.Cancel == this.未保存なら保存する() )
337 return; // 保存がキャンセルされた場合はここで中断。
339 this.ファイルを読み込む( ファイルパス );
341 protected void Act上書き保存する()
343 if( string.IsNullOrEmpty( this.編集中のファイル名 ) )
345 #region " ファイル名が未設定なら、初めての保存と見なし、ファイル保存ダイアログで保存ファイル名を指定させる。"
347 string 絶対パスファイル名 = this.ファイル保存ダイアログを開いてファイル名を取得する();
349 if( string.IsNullOrEmpty( 絶対パスファイル名 ) )
350 return; // ファイル保存ダイアログがキャンセルされたのならここで打ち切り。
352 this.作業フォルダパス = Path.GetDirectoryName( 絶対パスファイル名 ); // ダイアログでディレクトリを変更した場合、カレントディレクトリも変更されている。
353 this.編集中のファイル名 = Path.GetFileName( 絶対パスファイル名 );
359 Path.Combine( this.作業フォルダパス, this.編集中のファイル名 ),
360 プレイヤー用一時ファイルである: false );
362 protected void Act上書き保存する( string ファイルの絶対パス, bool プレイヤー用一時ファイルである )
364 #region " [保存中です] ポップアップを表示する。"
366 var msg = new Popupメッセージ(
367 Properties.Resources.MSG_保存中です + Environment.NewLine +
368 Properties.Resources.MSG_しばらくお待ち下さい );
377 #region " 選択モードだったら、全チップの選択を解除する。"
380 this.選択モード.全チップの選択を解除する();
383 #region " 出力するパス内の背景動画を検索する。"
385 this.textBox背景動画.Text =
386 ( from ファイル名 in Directory.GetFiles( Path.GetDirectoryName( ファイルの絶対パス ) )
387 where SSTFormat.スコア.背景動画のデフォルト拡張子s.Any( 拡張子名 => ( Path.GetExtension( ファイル名 ).ToLower() == 拡張子名 ) )
388 select ファイル名 ).FirstOrDefault(); // 複数あったら、最初に見つけたほうを採用。1つも見つからなければ null。
391 #region " SSTFファイルを出力する。"
393 this.譜面.SSTFファイルを書き出す(
395 $"# Created by SSTFEditor {this.メジャーバージョン番号}.{this.マイナーバージョン番号}.{this.リビジョン番号}.{this.ビルド番号}" );
398 #region " 出力したファイルのパスを、[ファイル]メニューの最近使ったファイル一覧に追加する。"
400 if( false == プレイヤー用一時ファイルである )
402 this.Config.ファイルを最近使ったファイルの一覧に追加する( ファイルの絶対パス );
403 this.ConfigのRecentUsedFilesをファイルメニューへ追加する();
410 #region " [保存中です] ポップアップを閉じる。"
416 // 最後に、ダイアログのゴミなどを消すために再描画。
419 if( false == プレイヤー用一時ファイルである )
423 protected void Act名前を付けて保存する()
425 #region " ユーザに保存ファイル名を入力させる。"
427 string 絶対パスファイル名 = this.ファイル保存ダイアログを開いてファイル名を取得する();
428 if( string.IsNullOrEmpty( 絶対パスファイル名 ) )
429 return; // キャンセルされたらここで中断。
431 this.作業フォルダパス = Path.GetDirectoryName( 絶対パスファイル名 );
432 this.編集中のファイル名 = Path.GetFileName( 絶対パスファイル名 );
438 this.未保存である = true; // ウィンドウタイトルに表示されているファイル名を変更するため、一度わざと true にする。
441 protected void Act終了する()
445 protected void Act元に戻す()
447 // Undo する対象を UndoRedoリストから取得する。
448 var cell = this.UndoRedo管理.Undoするセルを取得して返す();
456 this.UndoRedo用GUIのEnabledを設定する();
457 this.選択チップの有無に応じて編集用GUIのEnabledを設定する();
460 protected void Actやり直す()
462 // Redo する対象を UndoRedoリストから取得する。
463 var cell = this.UndoRedo管理.Redoするセルを取得して返す();
471 this.UndoRedo用GUIのEnabledを設定する();
472 this.選択チップの有無に応じて編集用GUIのEnabledを設定する();
475 protected void Act切り取る()
477 // 譜面にフォーカスがないなら、何もしない。
478 if( false == this.pictureBox譜面パネル.Focused )
485 protected void Actコピーする()
487 // 譜面にフォーカスがないなら何もしない。
488 if( false == this.pictureBox譜面パネル.Focused )
492 this.クリップボード.現在選択されているチップをボードにコピーする();
495 this.選択チップの有無に応じて編集用GUIのEnabledを設定する();
498 protected void Act貼り付ける( int 貼り付けを開始する譜面内絶対位置grid )
500 // 譜面にフォーカスがないなら何もしない。
501 if( false == this.pictureBox譜面パネル.Focused )
504 this.クリップボード.チップを指定位置から貼り付ける( 貼り付けを開始する譜面内絶対位置grid );
506 protected void Act削除する()
508 // 譜面にフォーカスがないなら何もしない。
509 if( false == this.pictureBox譜面パネル.Focused )
514 this.UndoRedo管理.トランザクション記録を開始する();
516 // 譜面が持つすべてのチップについて、選択されているチップがあれば削除する。
517 for( int i = this.譜面.SSTFormatScore.チップリスト.Count - 1; 0 <= i; i-- )
519 var chip = this.譜面.SSTFormatScore.チップリスト[ i ];
523 var chip変更前 = new SSTFormat.チップ( chip );
525 var cell = new UndoRedo.セル<SSTFormat.チップ>(
527 Undoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
528 変更対象.CopyFrom( 変更前 );
529 this.譜面.SSTFormatScore.チップリスト.Add( 変更対象 );
530 this.譜面.SSTFormatScore.チップリスト.Sort();
532 Redoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
533 this.譜面.SSTFormatScore.チップリスト.Remove( 変更対象 );
542 this.UndoRedo管理.セルを追加する( cell );
549 this.UndoRedo管理.トランザクション記録を終了する();
552 this.UndoRedo用GUIのEnabledを設定する();
553 this.選択チップの有無に応じて編集用GUIのEnabledを設定する();
557 protected void Actすべて選択する()
559 // 編集モードなら強制的に選択モードにする。
561 this.選択モードに切替えて関連GUIを設定する();
563 this.選択モード.全チップを選択する();
565 protected void Act選択モードにする()
567 this.選択モードに切替えて関連GUIを設定する();
569 protected void Act編集モードにする()
571 this.編集モードに切替えて関連GUIを設定する();
573 protected void Actモードを切替える()
577 this.編集モードに切替えて関連GUIを設定する();
581 this.選択モードに切替えて関連GUIを設定する();
584 protected void Act検索する()
586 this.選択モード.検索する(); // 現在のモードに関わらず、検索はすべて選択モードオブジェクトが行う。
588 protected void Actガイド間隔を変更する( int n分 )
592 if( !( new[] { 4, 6, 8, 12, 16, 24, 32, 48, 64, 128, 0 }.Contains( n分 ) ) )
593 throw new ArgumentException( $"不正なガイド間隔({n分})が指定されました。" );
596 #region " 新しいガイド間隔を設定する。"
599 this.譜面.現在のガイド間隔を変更する( n分 ); // 譜面オブジェクトとも共有。
602 #region " ガイド間隔関連GUI(メニュー、コンボボックス)を更新する。"
604 // 一度すべてのガイド間隔メニューのチェックをはずし、制定された分数のメニューだけをチェックする。
606 this.toolStripMenuItemガイド間隔4分.CheckState = CheckState.Unchecked;
607 this.toolStripMenuItemガイド間隔6分.CheckState = CheckState.Unchecked;
608 this.toolStripMenuItemガイド間隔8分.CheckState = CheckState.Unchecked;
609 this.toolStripMenuItemガイド間隔12分.CheckState = CheckState.Unchecked;
610 this.toolStripMenuItemガイド間隔16分.CheckState = CheckState.Unchecked;
611 this.toolStripMenuItemガイド間隔24分.CheckState = CheckState.Unchecked;
612 this.toolStripMenuItemガイド間隔32分.CheckState = CheckState.Unchecked;
613 this.toolStripMenuItemガイド間隔48分.CheckState = CheckState.Unchecked;
614 this.toolStripMenuItemガイド間隔64分.CheckState = CheckState.Unchecked;
615 this.toolStripMenuItemガイド間隔128分.CheckState = CheckState.Unchecked;
616 this.toolStripMenuItemガイド間隔フリー.CheckState = CheckState.Unchecked;
620 // Menu と ComboBox の2つを変更することでイベントが2つ発生し、最終的に
621 // Actガイド間隔を変更する() を立て続けに2回呼び出してしまうことになるが……、まぁよしとする。
624 this.toolStripMenuItemガイド間隔4分.CheckState = CheckState.Checked;
625 this.toolStripComboBoxガイド間隔.SelectedIndex = 0;
629 this.toolStripMenuItemガイド間隔6分.CheckState = CheckState.Checked;
630 this.toolStripComboBoxガイド間隔.SelectedIndex = 1;
634 this.toolStripMenuItemガイド間隔8分.CheckState = CheckState.Checked;
635 this.toolStripComboBoxガイド間隔.SelectedIndex = 2;
639 this.toolStripMenuItemガイド間隔12分.CheckState = CheckState.Checked;
640 this.toolStripComboBoxガイド間隔.SelectedIndex = 3;
644 this.toolStripMenuItemガイド間隔16分.CheckState = CheckState.Checked;
645 this.toolStripComboBoxガイド間隔.SelectedIndex = 4;
649 this.toolStripMenuItemガイド間隔24分.CheckState = CheckState.Checked;
650 this.toolStripComboBoxガイド間隔.SelectedIndex = 5;
654 this.toolStripMenuItemガイド間隔32分.CheckState = CheckState.Checked;
655 this.toolStripComboBoxガイド間隔.SelectedIndex = 6;
659 this.toolStripMenuItemガイド間隔48分.CheckState = CheckState.Checked;
660 this.toolStripComboBoxガイド間隔.SelectedIndex = 7;
664 this.toolStripMenuItemガイド間隔64分.CheckState = CheckState.Checked;
665 this.toolStripComboBoxガイド間隔.SelectedIndex = 8;
669 this.toolStripMenuItemガイド間隔128分.CheckState = CheckState.Checked;
670 this.toolStripComboBoxガイド間隔.SelectedIndex = 9;
674 this.toolStripMenuItemガイド間隔フリー.CheckState = CheckState.Checked;
675 this.toolStripComboBoxガイド間隔.SelectedIndex = 10;
682 this.pictureBox譜面パネル.Invalidate();
686 protected void Actガイド間隔を拡大する()
688 switch( this.現在のガイド間隔 )
691 case 6: this.Actガイド間隔を変更する( 4 ); break;
692 case 8: this.Actガイド間隔を変更する( 6 ); break;
693 case 12: this.Actガイド間隔を変更する( 8 ); break;
694 case 16: this.Actガイド間隔を変更する( 12 ); break;
695 case 24: this.Actガイド間隔を変更する( 16 ); break;
696 case 32: this.Actガイド間隔を変更する( 24 ); break;
697 case 48: this.Actガイド間隔を変更する( 32 ); break;
698 case 64: this.Actガイド間隔を変更する( 48 ); break;
699 case 128: this.Actガイド間隔を変更する( 64 ); break;
700 case 0: this.Actガイド間隔を変更する( 128 ); break;
703 protected void Actガイド間隔を縮小する()
705 switch( this.現在のガイド間隔 )
707 case 4: this.Actガイド間隔を変更する( 6 ); break;
708 case 6: this.Actガイド間隔を変更する( 8 ); break;
709 case 8: this.Actガイド間隔を変更する( 12 ); break;
710 case 12: this.Actガイド間隔を変更する( 16 ); break;
711 case 16: this.Actガイド間隔を変更する( 24 ); break;
712 case 24: this.Actガイド間隔を変更する( 32 ); break;
713 case 32: this.Actガイド間隔を変更する( 48 ); break;
714 case 48: this.Actガイド間隔を変更する( 64 ); break;
715 case 64: this.Actガイド間隔を変更する( 128 ); break;
716 case 128: this.Actガイド間隔を変更する( 0 ); break;
720 protected void Act譜面拡大率を変更する( int n倍 )
722 if( ( 1 > n倍 ) || ( 10 < n倍 ) )
723 throw new ArgumentException( $"不正な譜面拡大率({n倍})が指定されました。" );
725 this.toolStripComboBox譜面拡大率.SelectedIndex = ( n倍 - 1 );
728 protected void Act最初から再生する()
730 this.Act指定された小節の先頭から再生する( 小節番号: 0 );
732 protected void Act現在位置から再生する()
735 int 小節番号 = this.譜面.譜面内絶対位置gridにおける小節の番号と小節先頭の位置gridを返す( this.譜面.現在のカレントラインの譜面内絶対位置grid, out 位置grid );
736 this.Act指定された小節の先頭から再生する( 小節番号 );
738 protected void Act現在位置からBGMのみ再生する()
741 int 小節番号 = this.譜面.譜面内絶対位置gridにおける小節の番号と小節先頭の位置gridを返す( this.譜面.現在のカレントラインの譜面内絶対位置grid, out 位置grid );
742 this.Act指定された小節の先頭から再生する( 小節番号, 仮想ドラムを使う: false );
744 protected void Act指定された小節の先頭から再生する( int 小節番号, bool 仮想ドラムを使う = true )
746 if( string.IsNullOrEmpty( this.Viewerの絶対パスファイル名 ) ||
747 ( false == File.Exists( this.Viewerの絶対パスファイル名 ) ) )
750 // 前回のテンポラリファイルが存在していれば削除する。
751 if( File.Exists( this.最後にプレイヤーに渡した一時ファイル名 ) )
752 File.Delete( this.最後にプレイヤーに渡した一時ファイル名 );
754 // 譜面を新しくテンポラリファイルとして出力する。
757 this.最後にプレイヤーに渡した一時ファイル名 = Path.Combine( this.作業フォルダパス, Path.GetRandomFileName() );
758 } while( File.Exists( this.最後にプレイヤーに渡した一時ファイル名 ) ); // 同一名のファイルが存在してたらもう一度。(まずないだろうが)
761 this.最後にプレイヤーに渡した一時ファイル名,
762 プレイヤー用一時ファイルである: true ); // 一時ファイルなので、「最近使ったファイル一覧」には残さない。
765 string 仮想ドラムオプション = ( 仮想ドラムを使う ) ? @" -h" : @"";
767 this.Viewerの絶対パスファイル名,
768 $"\"{this.最後にプレイヤーに渡した一時ファイル名}\" -p {小節番号.ToString()}{仮想ドラムオプション}" );
770 protected void Act再生を停止する()
772 if( string.IsNullOrEmpty( this.Viewerの絶対パスファイル名 ) ||
773 ( false == File.Exists( this.Viewerの絶対パスファイル名 ) ) )
776 Process.Start( this.Viewerの絶対パスファイル名, @"-s" );
778 protected void Actオプションを設定する()
780 using( var dialog = new オプションダイアログ() )
782 // Config の現在の値をダイアログへ反映する。
783 dialog.checkBoxオートフォーカス.CheckState = ( this.Config.AutoFocus ) ? CheckState.Checked : CheckState.Unchecked;
784 dialog.checkBox最近使用したファイル.CheckState = ( this.Config.ShowRecentUsedFiles ) ? CheckState.Checked : CheckState.Unchecked;
785 dialog.numericUpDown最近使用したファイルの最大表示個数.Value = this.Config.MaxOfUsedRecentFiles;
787 if( DialogResult.OK == dialog.ShowDialog( this ) )
789 // 決定された値をダイアログから Config に反映する。
790 this.Config.AutoFocus = dialog.checkBoxオートフォーカス.Checked;
791 this.Config.ShowRecentUsedFiles = dialog.checkBox最近使用したファイル.Checked;
792 this.Config.MaxOfUsedRecentFiles = (int) dialog.numericUpDown最近使用したファイルの最大表示個数.Value;
795 this.ConfigのRecentUsedFilesをファイルメニューへ追加する();
799 // 画面を再描画してダイアログのゴミを消す。
802 protected void Actバージョンを表示する()
804 using( var dialog = new バージョン表示ダイアログ() )
805 dialog.ShowDialog( this );
807 protected void Act小節長倍率を変更する( int 小節番号 )
813 #region " 変更後の小節長倍率をユーザに入力させる。"
815 var db現在の小節長倍率 = this.譜面.SSTFormatScore.小節長倍率を取得する( 小節番号 );
816 using( var dialog = new 小節長倍率入力ダイアログ( 小節番号 ) )
818 dialog.倍率 = (float) db現在の小節長倍率;
819 dialog.後続も全部変更する = false;
821 if( DialogResult.OK != dialog.ShowDialog( this ) ) // キャンセルされたらここで中断。
824 変更後倍率 = (double) dialog.倍率;
825 変更終了小節番号 = ( dialog.後続も全部変更する ) ? this.譜面.SSTFormatScore.最大小節番号 : 小節番号;
833 this.UndoRedo管理.トランザクション記録を開始する();
835 for( int i = 変更開始小節番号; i <= 変更終了小節番号; i++ )
837 var 変更前倍率 = this.譜面.SSTFormatScore.小節長倍率を取得する( i );
839 #region " 新しい小節長倍率を設定する。"
841 var cell = new UndoRedo.セル<double>(
843 Undoアクション: ( 変更対象, 変更前, 変更後, 対象小節番号, 任意2 ) => {
844 this.譜面.SSTFormatScore.小節長倍率を設定する( (int) 対象小節番号, 変更前 );
847 Redoアクション: ( 変更対象, 変更前, 変更後, 対象小節番号, 任意2 ) => {
848 this.譜面.SSTFormatScore.小節長倍率を設定する( (int) 対象小節番号, 変更後 );
857 this.UndoRedo管理.セルを追加する( cell );
861 #region " チップを移動または削除する。"
863 int 変化量grid = (int) ( ( 変更後倍率 - 変更前倍率 ) * this.GRID_PER_PART );
865 for( int j = this.譜面.SSTFormatScore.チップリスト.Count - 1; j >= 0; j-- ) // 削除する場合があるので後ろからカウントする。
867 var chip = this.譜面.SSTFormatScore.チップリスト[ j ];
869 // (A) 変更対象の小節内のチップ → 移動なし。カウント変更あり。小節はみ出しチェックあり。
872 #region " 小節からはみ出したチップは、削除する。"
874 int 次小節の先頭位置grid = this.譜面.小節先頭の譜面内絶対位置gridを返す( i ) + (int) ( 変更後倍率 * this.GRID_PER_PART );
875 if( 次小節の先頭位置grid <= chip.譜面内絶対位置grid )
877 var chip変更前 = new SSTFormat.チップ( chip );
879 var cc = new UndoRedo.セル<SSTFormat.チップ>(
881 Undoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
882 変更対象.CopyFrom( 変更前 );
883 this.譜面.SSTFormatScore.チップリスト.Add( 変更対象 );
884 this.譜面.SSTFormatScore.チップリスト.Sort();
887 Redoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
888 this.譜面.SSTFormatScore.チップリスト.Remove( 変更対象 );
897 this.UndoRedo管理.セルを追加する( cc );
902 #region " 小節からはみ出さなかったチップは、カウント(小節解像度と小節内位置)を変更する。"
906 // 解像度が小さいと計算結果がおかしくなるので、無条件に解像度を上げる。
908 int 十分に大きな値 = this.GRID_PER_PART; // 充分に大きい数なら何でもいい。
909 if( 十分に大きな値 > chip.小節解像度 ) // 何度も乗算されたら値が肥大化しまくるので、制限をかける。
911 chip.小節解像度 *= 十分に大きな値;
912 chip.小節内位置 *= 十分に大きな値;
915 // 小節解像度を変更する。(小節内位置は変更しない。)
916 chip.小節解像度 = (int) ( 変更後倍率 * chip.小節解像度 );
922 // (B) 変更対象より先の小節内のチップ → 移動あり。カウントなし。小節はみ出しチェックなし。
923 else if( i < chip.小節番号 )
925 #region " チップを n変化量grid 移動する。"
927 var cc = new UndoRedo.セル<SSTFormat.チップ>(
929 Undoアクション: ( 変更対象, 変更前, 変更後, _変化量grid, 任意2 ) => {
930 変更対象.譜面内絶対位置grid -= (int) _変化量grid;
933 Redoアクション: ( 変更対象, 変更前, 変更後, _変化量grid, 任意2 ) => {
934 変更対象.譜面内絶対位置grid += (int) _変化量grid;
943 this.UndoRedo管理.セルを追加する( cc );
955 this.UndoRedo管理.トランザクション記録を終了する();
958 this.UndoRedo用GUIのEnabledを設定する();
962 protected void Act小節を挿入する( int 挿入前小節番号 )
964 // 挿入する新しい小節の小節長は、直前の(挿入前小節番号-1 の小節)と同じサイズとする。
965 double 小節長倍率 = ( 0 < 挿入前小節番号 ) ? this.譜面.SSTFormatScore.小節長倍率を取得する( 挿入前小節番号 - 1 ) : 1.0;
970 this.UndoRedo管理.トランザクション記録を開始する();
972 #region " 後方のチップを移動する。"
974 int 挿入に伴う増加量grid = (int) ( this.GRID_PER_PART * 小節長倍率 );
976 foreach( var chip in this.譜面.SSTFormatScore.チップリスト )
978 if( 挿入前小節番号 <= chip.小節番号 )
980 var cell = new UndoRedo.セル<SSTFormat.チップ>(
982 Undoアクション: ( 変更対象, 変更前, 変更後, _挿入に伴う増加量grid, 任意2 ) => {
984 変更対象.譜面内絶対位置grid -= (int) _挿入に伴う増加量grid;
986 Redoアクション: ( 変更対象, 変更前, 変更後, _挿入に伴う増加量grid, 任意2 ) => {
988 変更対象.譜面内絶対位置grid += (int) _挿入に伴う増加量grid;
996 this.UndoRedo管理.セルを追加する( cell );
1002 #region " 後方の小節長倍率を移動する。"
1004 var cc = new UndoRedo.セル<double>(
1006 Undoアクション: ( 変更対象, 変更前, 変更後, _挿入前小節番号, 任意2 ) => {
1007 this.譜面.SSTFormatScore.小節長倍率リスト.RemoveAt( (int) _挿入前小節番号 );
1010 Redoアクション: ( 変更対象, 変更前, 変更後, _挿入前小節番号, 任意2 ) => {
1011 this.譜面.SSTFormatScore.小節長倍率リスト.Insert( (int) _挿入前小節番号, 小節長倍率 );
1020 this.UndoRedo管理.セルを追加する( cc );
1027 this.UndoRedo管理.トランザクション記録を終了する();
1030 this.UndoRedo用GUIのEnabledを設定する();
1035 protected void Act小節を削除する( int 削除する小節番号 )
1037 double 削除する小節の小節長倍率 = this.譜面.SSTFormatScore.小節長倍率を取得する( 削除する小節番号 );
1042 this.UndoRedo管理.トランザクション記録を開始する();
1044 #region " 削除される小節内のチップをすべて削除する。"
1046 for( int i = this.譜面.SSTFormatScore.チップリスト.Count - 1; i >= 0; i-- )
1048 var chip = this.譜面.SSTFormatScore.チップリスト[ i ];
1050 if( 削除する小節番号 == chip.小節番号 )
1052 var chip変更前 = new SSTFormat.チップ( chip );
1054 var cell = new UndoRedo.セル<SSTFormat.チップ>(
1056 Undoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
1057 変更対象.CopyFrom( 変更前 );
1058 this.譜面.SSTFormatScore.チップリスト.Add( 変更対象 );
1059 this.譜面.SSTFormatScore.チップリスト.Sort();
1061 Redoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
1062 this.譜面.SSTFormatScore.チップリスト.Remove( 変更対象 );
1071 this.UndoRedo管理.セルを追加する( cell );
1077 #region " 後方のチップを移動する。"
1079 int 削除に伴う減少量grid = (int) ( this.GRID_PER_PART * 削除する小節の小節長倍率 );
1081 foreach( var chip in this.譜面.SSTFormatScore.チップリスト )
1083 if( 削除する小節番号 < chip.小節番号 )
1085 var cell = new UndoRedo.セル<SSTFormat.チップ>(
1087 Undoアクション: ( 変更対象, 変更前, 変更後, _削除に伴う減少量grid, 任意2 ) => {
1089 変更対象.譜面内絶対位置grid += (int) _削除に伴う減少量grid;
1091 Redoアクション: ( 変更対象, 変更前, 変更後, _削除に伴う減少量grid, 任意2 ) => {
1093 変更対象.譜面内絶対位置grid -= (int) _削除に伴う減少量grid;
1101 this.UndoRedo管理.セルを追加する( cell );
1107 #region " 後方の小節長倍率を移動する。"
1109 var cc = new UndoRedo.セル<double>(
1111 Undoアクション: ( 変更対象, 変更前, 変更後, _削除する小節番号, 任意2 ) => {
1112 this.譜面.SSTFormatScore.小節長倍率リスト.Insert( (int) _削除する小節番号, 変更前 );
1115 Redoアクション: ( 変更対象, 変更前, 変更後, _削除する小節番号, 任意2 ) => {
1116 this.譜面.SSTFormatScore.小節長倍率リスト.RemoveAt( (int) _削除する小節番号 );
1120 変更前の値: 削除する小節の小節長倍率,
1125 this.UndoRedo管理.セルを追加する( cc );
1132 this.UndoRedo管理.トランザクション記録を終了する();
1135 this.UndoRedo用GUIのEnabledを設定する();
1139 protected void Act小節の先頭へ移動する( int 小節番号 )
1144 else if( 小節番号 > this.譜面.SSTFormatScore.最大小節番号 )
1145 小節番号 = this.譜面.SSTFormatScore.最大小節番号;
1147 // 垂直スクロールバーを移動させると、画面も自動的に移動する。
1148 var bar = this.vScrollBar譜面用垂直スクロールバー;
1149 bar.Value = ( ( bar.Maximum + 1 ) - bar.LargeChange ) - this.譜面.小節先頭の譜面内絶対位置gridを返す( 小節番号 );
1154 protected void エディタを初期化する()
1156 this.編集中のファイル名 = null;
1158 #region " 各種オブジェクトを生成する。"
1161 this.譜面 = new C譜面( this ); // 譜面は、選択・編集モードよりも先に生成すること。
1163 this.UndoRedo管理 = new UndoRedo.管理();
1164 this.選択モード = new 選択モード( this );
1165 this.編集モード = new 編集モード( this );
1166 this.クリップボード = new クリップボード( this );
1174 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
1175 this.textBox曲名.Clear();
1177 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
1178 this.textBox説明.Clear();
1181 #region " Viewer 再生 "
1183 this.Viewer再生関連GUIのEnabledを設定する();
1188 this.Actガイド間隔を変更する( 16 ); // 初期値は 1/16。
1193 this.Act譜面拡大率を変更する( 1 ); // 初期値は x1.0。
1196 #region " Undo/Redo "
1198 this.次のプロパティ変更がUndoRedoリストに載るようにする();
1199 this.UndoRedo用GUIのEnabledを設定する();
1202 #region " 垂直スクロールバー "
1204 this.vScrollBar譜面用垂直スクロールバー.Minimum = 0;
1205 this.vScrollBar譜面用垂直スクロールバー.Maximum = ( this.譜面.全小節の高さgrid - 1 );
1206 this.vScrollBar譜面用垂直スクロールバー.SmallChange = ( this.GRID_PER_PART / 16 );
1207 this.vScrollBar譜面用垂直スクロールバー.LargeChange = this.GRID_PER_PART;
1208 this.vScrollBar譜面用垂直スクロールバー.Value = this.vScrollBar譜面用垂直スクロールバー.Maximum - this.vScrollBar譜面用垂直スクロールバー.LargeChange;
1214 this.編集モードに切替えて関連GUIを設定する();
1215 this.未保存である = false;
1217 protected DialogResult 未保存なら保存する()
1219 #region " 既に保存済みなら何もしない。"
1221 if( false == this.未保存である )
1222 return DialogResult.OK;
1225 #region "[編集中のデータを保存しますか?] ダイアログを表示し、回答を待つ。"
1227 var result = MessageBox.Show(
1228 Properties.Resources.MSG_編集中のデータを保存しますか,
1229 Properties.Resources.MSG_確認ダイアログのタイトル,
1230 MessageBoxButtons.YesNoCancel,
1231 MessageBoxIcon.Question,
1232 MessageBoxDefaultButton.Button1 );
1235 #region " YES なら上書き保存する。"
1237 if( DialogResult.Yes == result )
1241 #region " 画面を再描画してダイアログを消去する。"
1247 return result; // ダイアログの結果を返す。
1249 protected string ファイル保存ダイアログを開いてファイル名を取得する()
1251 DialogResult result;
1254 // ダイアログでファイル名を取得する。
1255 using( var dialog = new SaveFileDialog() {
1257 Filter = "SSTFファイル(*.sstf)|*.sstf",
1259 InitialDirectory = this.作業フォルダパス,
1262 result = dialog.ShowDialog( this );
1263 ファイル名 = dialog.FileName;
1266 // 画面を再描画してダイアログのゴミを消去する。
1269 // キャンセルされたら ""(空文字列)を返す。
1270 if( DialogResult.OK != result )
1273 // ファイルの拡張子を .sstf に変更。
1274 if( 0 == Path.GetExtension( ファイル名 ).Length )
1275 ファイル名 = Path.ChangeExtension( ファイル名, ".sstf" );
1279 protected void ファイルを読み込む( string ファイル名 )
1283 #region " [読み込み中です] ポップアップを表示する。"
1285 var msg = new Popupメッセージ(
1286 Properties.Resources.MSG_読み込み中です + Environment.NewLine +
1287 Properties.Resources.MSG_しばらくお待ち下さい );
1296 this.譜面.曲データファイルを読み込む( ファイル名 );
1298 // 最低でも 10 小節は存在させる。
1299 for( int n = this.譜面.SSTFormatScore.最大小節番号 + 1; n < 9; n++ )
1302 string 読み込み時の拡張子 = Path.GetExtension( ファイル名 ).ToLower();
1303 this.編集中のファイル名 = Path.ChangeExtension( Path.GetFileName( ファイル名 ), ".sstf" ); // 読み込んだファイルの拡張子を .sstf に変換。
1304 this.作業フォルダパス = Path.GetDirectoryName( ファイル名 );
1306 // 読み込んだファイルを [ファイル]メニューの最近使ったファイル一覧に追加する。
1307 this.Config.ファイルを最近使ったファイルの一覧に追加する( Path.Combine( this.作業フォルダパス, this.編集中のファイル名 ) );
1308 this.ConfigのRecentUsedFilesをファイルメニューへ追加する();
1311 譜面.SSTFormatScore.背景動画ファイル名 =
1312 ( from file in Directory.GetFiles( Path.GetDirectoryName( this.作業フォルダパス ) )
1313 where SSTFormat.スコア.背景動画のデフォルト拡張子s.Any( 拡張子名 => ( Path.GetExtension( file ).ToLower() == 拡張子名 ) )
1314 select file ).FirstOrDefault(); // 複数あったら、最初に見つけたほうを採用。1つも見つからなければ null。
1315 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
1316 this.textBox曲名.Text = 譜面.SSTFormatScore.Header.曲名;
1317 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
1318 this.textBox説明.Text = 譜面.SSTFormatScore.Header.説明文;
1319 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
1320 this.textBox背景動画.Text = Path.GetFileName( 譜面.SSTFormatScore.背景動画ファイル名 );
1321 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
1322 this.textBoxメモ.Text = ( this.譜面.SSTFormatScore.dicメモ.ContainsKey( 0 ) ) ? this.譜面.SSTFormatScore.dicメモ[ 0 ] : "";
1324 // ウィンドウのタイトルバーの表示変更(str編集中のファイル名 が確定した後に)
1325 this.未保存である = true; // 以前の状態によらず、確実に更新するようにする。
1327 // sstf 以外を読み込んだ場合は、未保存状態のままとする。
1328 if( 読み込み時の拡張子.ToLower() == ".sstf" )
1329 this.未保存である = false;
1331 catch( InvalidDataException )
1334 Properties.Resources.MSG_対応していないファイルです,
1335 Properties.Resources.MSG_確認ダイアログのタイトル,
1336 MessageBoxButtons.OK );
1339 #region "「読み込み中です」ポップアップを閉じる。 "
1345 // 最後に、ダイアログのゴミなどを消すために画面を再描画する。
1348 protected enum タブ種別 : int { 基本情報 = 0 }
1349 protected void タブを選択する( タブ種別 eタブ種別 )
1351 this.tabControl情報タブコンテナ.SelectedIndex = (int) eタブ種別;
1353 protected void 次のプロパティ変更がUndoRedoリストに載らないようにする()
1355 UndoRedo.管理.UndoRedoした直後である = true;
1357 protected void 次のプロパティ変更がUndoRedoリストに載るようにする()
1359 UndoRedo.管理.UndoRedoした直後である = false;
1361 protected void 垂直スクロールバーと譜面の上下位置を調整する()
1363 var bar = this.vScrollBar譜面用垂直スクロールバー;
1364 var box = this.pictureBox譜面パネル;
1365 var panel2 = this.splitContainer分割パネルコンテナ.Panel2;
1367 // 譜面パネルの長さをパネルに合わせて調整する。
1368 box.ClientSize = new Size(
1369 box.ClientSize.Width,
1370 panel2.ClientSize.Height - box.Location.Y );
1372 // 現在のバーの位置を割合で記憶する。
1373 var bar率 = (double) bar.Value / (double) ( bar.Maximum - bar.Minimum );
1375 // 新しい値域を設定した後、バーの位置を記憶しておいた割合で設定。
1377 bar.Maximum = this.譜面.全小節の高さgrid - 1;
1378 bar.Value = (int) ( ( bar.Maximum - bar.Minimum ) * bar率 );
1380 // 譜面長さが画面長さより短いなら、スクロールバーを表示しない。
1381 bar.Enabled = ( bar.Maximum > bar.LargeChange ) ? true : false;
1383 protected void Viewer再生関連GUIのEnabledを設定する()
1385 if( File.Exists( this.Viewerの絶対パスファイル名 ) )
1387 // (A) Viewer が存在するなら、各GUIは有効。
1389 this.toolStripButton先頭から再生.Enabled = true;
1390 this.toolStripButton現在位置から再生.Enabled = true;
1391 this.toolStripButton現在位置からBGMのみ再生.Enabled = true;
1392 this.toolStripButton再生停止.Enabled = true;
1394 this.toolStripMenuItem先頭から再生.Enabled = true;
1395 this.toolStripMenuItem現在位置から再生.Enabled = true;
1396 this.toolStripMenuItem現在位置からBGMのみ再生.Enabled = true;
1397 this.toolStripMenuItem再生停止.Enabled = true;
1401 // (B) Viewer が存在しないなら、各GUIは無効。
1403 this.toolStripButton先頭から再生.Enabled = false;
1404 this.toolStripButton現在位置から再生.Enabled = false;
1405 this.toolStripButton現在位置からBGMのみ再生.Enabled = false;
1406 this.toolStripButton再生停止.Enabled = false;
1408 this.toolStripMenuItem先頭から再生.Enabled = false;
1409 this.toolStripMenuItem現在位置から再生.Enabled = false;
1410 this.toolStripMenuItem現在位置からBGMのみ再生.Enabled = false;
1411 this.toolStripMenuItem再生停止.Enabled = false;
1414 protected void ConfigのRecentUsedFilesをファイルメニューへ追加する()
1416 #region " [ファイル] メニューから、[最近使ったファイルの一覧] をクリアする。"
1418 for( int i = 0; i < this.toolStripMenuItemファイル.DropDownItems.Count; i++ )
1420 var item = this.toolStripMenuItemファイル.DropDownItems[ i ];
1422 // ↓削除したくないサブメニューの一覧。これ以外のサブメニュー項目はすべて削除する。
1423 if( item != this.toolStripMenuItem新規作成 &&
1424 item != this.toolStripMenuItem開く &&
1425 item != this.toolStripMenuItem上書き保存 &&
1426 item != this.toolStripMenuItem名前を付けて保存 &&
1427 item != this.toolStripSeparator1 &&
1428 item != this.toolStripMenuItem終了 )
1430 this.toolStripMenuItemファイル.DropDownItems.Remove( item );
1431 i = -1; // 要素数が変わったので列挙しなおし。RemoveAll() はないのか。
1437 if( ( false == this.Config.ShowRecentUsedFiles ) || // 表示しない or
1438 ( 0 == this.Config.RecentUsedFiles.Count ) ) // 履歴が 0 件
1441 #region " Config が持つ履歴にそって、[ファイル] メニューにサブメニュー項目リストを追加する(ただし最大表示数まで)。"
1443 // [File] のサブメニューリストに項目が1つでもある場合は、履歴サブメニュー項目を追加する前に、[終了] の下にセパレータを入れる。手動で。
1444 bool セパレータの追加がまだ = true;
1446 // すべての [最近使ったファイル] について...
1447 for( int i = 0; i < this.Config.RecentUsedFiles.Count; i++ )
1450 if( this.Config.MaxOfUsedRecentFiles <= i )
1453 // ファイルパスを、サブメニュー項目として [ファイル] メニューに追加する。
1454 string ファイルパス = this.Config.RecentUsedFiles[ i ];
1455 if( string.IsNullOrEmpty( ファイルパス ) )
1458 // セパレータの追加がまだなら追加する。
1461 this.toolStripMenuItemファイル.DropDownItems.Add( new ToolStripSeparator() { Size = this.toolStripSeparator1.Size } );
1462 セパレータの追加がまだ = false;
1465 // ToolStripMenuItem を手動で作って [ファイル] のサブメニューリストに追加する。
1466 var item = new ToolStripMenuItem() {
1467 Name = "最近使ったファイル" + i,
1468 Size = this.toolStripMenuItem終了.Size,
1469 Text = "&" + i + " " + ファイルパス,
1471 item.Click += new EventHandler( this.toolStripMenuItem最近使ったファイル_Click );
1472 this.toolStripMenuItemファイル.DropDownItems.Add( item );
1474 // 追加したファイルが既に存在していないなら項目を無効化(グレー表示)する。
1475 if( false == File.Exists( ファイルパス ) )
1476 item.Enabled = false;
1481 protected Point 現在のマウス位置を譜面パネル内座標pxに変換して返す()
1483 return this.pictureBox譜面パネル.PointToClient( new Point( Cursor.Position.X, Cursor.Position.Y ) );
1485 protected void 現在のチップ音量をツールバーに表示する()
1487 this.toolStripLabel音量.Text = ( this.dic音量ラベル.ContainsKey( this.現在のチップ音量 ) ) ? this.dic音量ラベル[ this.現在のチップ音量 ] : @"???";
1494 protected void メインフォーム_DragDrop( object sender, DragEventArgs e )
1496 string[] data = (string[]) e.Data.GetData( DataFormats.FileDrop );
1498 if( 1 <= data.Length )
1499 this.Act指定されたファイルを開く( data[ 0 ] ); // Dropされたファイルが複数個あっても、先頭のファイルだけを有効とする。
1501 protected void メインフォーム_DragEnter( object sender, DragEventArgs e )
1503 if( e.Data.GetDataPresent( DataFormats.FileDrop ) )
1505 e.Effect = DragDropEffects.Copy; // ファイルならコピーと見なす(カーソルがコピー型になる)
1509 e.Effect = DragDropEffects.None; // ファイルじゃないなら無視(カーソル変化なし)
1512 protected void メインフォーム_FormClosing( object sender, FormClosingEventArgs e )
1514 if( DialogResult.Cancel == this.未保存なら保存する() )
1528 protected void toolStripMenuItem新規作成_Click( object sender, EventArgs e )
1532 protected void toolStripMenuItem開く_Click( object sender, EventArgs e )
1536 protected void toolStripMenuItem上書き保存_Click( object sender, EventArgs e )
1540 protected void toolStripMenuItem名前を付けて保存_Click( object sender, EventArgs e )
1542 this.Act名前を付けて保存する();
1544 protected void toolStripMenuItem終了_Click( object sender, EventArgs e )
1548 protected void toolStripMenuItem最近使ったファイル_Click( object sender, EventArgs e )
1550 // ※このイベントハンドラに対応する「toolStripMenuItem最近使ったファイル」というアイテムはデザイナにはないので注意。
1551 // 「this.t最近使ったファイルをFileメニューへ追加する()」の中で、手動で作って追加したアイテムに対するハンドラである。
1553 this.Act指定されたファイルを開く( ( (ToolStripMenuItem) sender ).Text.Substring( 3 ) );
1557 protected void toolStripMenuItem元に戻す_Click( object sender, EventArgs e )
1561 protected void toolStripMenuItemやり直す_Click( object sender, EventArgs e )
1565 protected void toolStripMenuItem切り取り_Click( object sender, EventArgs e )
1569 protected void toolStripMenuItemコピー_Click( object sender, EventArgs e )
1573 protected void toolStripMenuItem貼り付け_Click( object sender, EventArgs e )
1575 var マウスの位置 = this.現在のマウス位置を譜面パネル内座標pxに変換して返す();
1577 // (A) マウスが譜面上になかった → 表示領域下辺から貼り付ける。
1578 if( ( ( 0 > マウスの位置.X ) || ( 0 > マウスの位置.Y ) ) ||
1579 ( ( マウスの位置.X > this.譜面パネルサイズ.Width ) || ( マウスの位置.Y > this.譜面パネルサイズ.Height ) ) )
1581 this.Act貼り付ける( this.譜面.現在の譜面表示下辺の譜面内絶対位置grid );
1583 // (B) マウスが譜面上にある → そこから貼り付ける。
1586 this.Act貼り付ける( this.譜面.譜面パネル内Y座標pxにおける譜面内絶対位置gridをガイド幅単位で返す( マウスの位置.Y ) );
1589 protected void toolStripMenuItem削除_Click( object sender, EventArgs e )
1593 protected void toolStripMenuItemすべて選択_Click( object sender, EventArgs e )
1597 protected void toolStripMenuItem選択モード_Click( object sender, EventArgs e )
1599 this.選択モードに切替えて関連GUIを設定する();
1601 protected void toolStripMenuItem編集モード_Click( object sender, EventArgs e )
1603 this.編集モードに切替えて関連GUIを設定する();
1605 protected void toolStripMenuItemモード切替え_Click( object sender, EventArgs e )
1609 this.編集モードに切替えて関連GUIを設定する();
1613 this.選択モードに切替えて関連GUIを設定する();
1616 protected void toolStripMenuItem検索_Click( object sender, EventArgs e )
1622 protected void toolStripMenuItemガイド間隔4分_Click( object sender, EventArgs e )
1624 this.Actガイド間隔を変更する( 4 );
1626 protected void toolStripMenuItemガイド間隔6分_Click( object sender, EventArgs e )
1628 this.Actガイド間隔を変更する( 6 );
1630 protected void toolStripMenuItemガイド間隔8分_Click( object sender, EventArgs e )
1632 this.Actガイド間隔を変更する( 8 );
1634 protected void toolStripMenuItemガイド間隔12分_Click( object sender, EventArgs e )
1636 this.Actガイド間隔を変更する( 12 );
1638 protected void toolStripMenuItemガイド間隔16分_Click( object sender, EventArgs e )
1640 this.Actガイド間隔を変更する( 16 );
1642 protected void toolStripMenuItemガイド間隔24分_Click( object sender, EventArgs e )
1644 this.Actガイド間隔を変更する( 24 );
1646 protected void toolStripMenuItemガイド間隔32分_Click( object sender, EventArgs e )
1648 this.Actガイド間隔を変更する( 32 );
1650 protected void toolStripMenuItemガイド間隔48分_Click( object sender, EventArgs e )
1652 this.Actガイド間隔を変更する( 48 );
1654 protected void toolStripMenuItemガイド間隔64分_Click( object sender, EventArgs e )
1656 this.Actガイド間隔を変更する( 64 );
1658 protected void toolStripMenuItemガイド間隔128分_Click( object sender, EventArgs e )
1660 this.Actガイド間隔を変更する( 128 );
1662 protected void toolStripMenuItemガイド間隔フリー_Click( object sender, EventArgs e )
1664 this.Actガイド間隔を変更する( 0 );
1666 protected void toolStripMenuItemガイド間隔拡大_Click( object sender, EventArgs e )
1668 this.Actガイド間隔を拡大する();
1670 protected void toolStripMenuItemガイド間隔縮小_Click( object sender, EventArgs e )
1672 this.Actガイド間隔を縮小する();
1676 protected void toolStripMenuItem先頭から再生_Click( object sender, EventArgs e )
1680 protected void toolStripMenuItem現在位置から再生_Click( object sender, EventArgs e )
1682 this.Act現在位置から再生する();
1684 protected void toolStripMenuItem現在位置からBGMのみ再生_Click( object sender, EventArgs e )
1686 this.Act現在位置からBGMのみ再生する();
1688 protected void toolStripMenuItem再生停止_Click( object sender, EventArgs e )
1694 protected void toolStripMenuItemオプション_Click( object sender, EventArgs e )
1696 this.Actオプションを設定する();
1700 protected void toolStripMenuItemバージョン_Click( object sender, EventArgs e )
1702 this.Actバージョンを表示する();
1708 protected void toolStripButton新規作成_Click( object sender, EventArgs e )
1712 protected void toolStripButton開く_Click( object sender, EventArgs e )
1716 protected void toolStripButton上書き保存_Click( object sender, EventArgs e )
1720 protected void toolStripButton切り取り_Click( object sender, EventArgs e )
1724 protected void toolStripButtonコピー_Click( object sender, EventArgs e )
1728 protected void toolStripButton貼り付け_Click( object sender, EventArgs e )
1730 var マウスの位置 = this.現在のマウス位置を譜面パネル内座標pxに変換して返す();
1732 // (A) マウスが譜面上になかった → 表示領域下辺から貼り付ける。
1733 if( ( ( マウスの位置.X < 0 ) || ( マウスの位置.Y < 0 ) ) ||
1734 ( ( マウスの位置.X > this.譜面パネルサイズ.Width ) || ( マウスの位置.Y > this.譜面パネルサイズ.Height ) ) )
1736 this.Act貼り付ける( this.譜面.現在の譜面表示下辺の譜面内絶対位置grid );
1738 // (B) マウスが譜面上にある → そこから貼り付ける。
1741 this.Act貼り付ける( this.譜面.譜面パネル内Y座標pxにおける譜面内絶対位置gridをガイド幅単位で返す( マウスの位置.Y ) );
1744 protected void toolStripButton削除_Click( object sender, EventArgs e )
1749 protected void toolStripButton元に戻す_Click( object sender, EventArgs e )
1753 protected void toolStripButtonやり直す_Click( object sender, EventArgs e )
1758 protected void toolStripComboBox譜面拡大率_SelectedIndexChanged( object sender, EventArgs e )
1760 this.Act譜面拡大率を変更する( this.toolStripComboBox譜面拡大率.SelectedIndex + 1 );
1762 protected void toolStripComboBoxガイド間隔_SelectedIndexChanged( object sender, EventArgs e )
1764 switch( this.toolStripComboBoxガイド間隔.SelectedIndex )
1767 this.Actガイド間隔を変更する( 4 );
1771 this.Actガイド間隔を変更する( 6 );
1775 this.Actガイド間隔を変更する( 8 );
1779 this.Actガイド間隔を変更する( 12 );
1783 this.Actガイド間隔を変更する( 16 );
1787 this.Actガイド間隔を変更する( 24 );
1791 this.Actガイド間隔を変更する( 32 );
1795 this.Actガイド間隔を変更する( 48 );
1799 this.Actガイド間隔を変更する( 64 );
1803 this.Actガイド間隔を変更する( 128 );
1807 this.Actガイド間隔を変更する( 0 );
1812 protected void toolStripButton選択モード_Click( object sender, EventArgs e )
1816 protected void toolStripButton編集モード_Click( object sender, EventArgs e )
1821 protected void toolStripButton先頭から再生_Click( object sender, EventArgs e )
1825 protected void toolStripButton現在位置から再生_Click( object sender, EventArgs e )
1827 this.Act現在位置から再生する();
1829 protected void toolStripButton現在位置からBGMのみ再生_Click( object sender, EventArgs e )
1831 this.Act現在位置からBGMのみ再生する();
1833 protected void toolStripButton再生停止_Click( object sender, EventArgs e )
1838 protected void toolStripButton音量Down_Click( object sender, EventArgs e )
1840 int 新音量 = this.現在のチップ音量 - 1;
1841 this.現在のチップ音量 = ( 新音量 < メインフォーム.最小音量 ) ? メインフォーム.最小音量 : 新音量;
1843 this.現在のチップ音量をツールバーに表示する();
1845 protected void toolStripButton音量UP_Click( object sender, EventArgs e )
1847 int 新音量 = this.現在のチップ音量 + 1;
1848 this.現在のチップ音量 = ( 新音量 > メインフォーム.最大音量 ) ? メインフォーム.最大音量 : 新音量;
1850 this.現在のチップ音量をツールバーに表示する();
1854 #region " 分割パネルコンテナ、譜面パネル、スクロールバー "
1856 protected void pictureBox譜面パネル_MouseClick( object sender, MouseEventArgs e )
1859 this.pictureBox譜面パネル.Focus();
1861 // 選択・編集モードオブジェクトのいずれかへ処理を引き継ぐ。
1864 this.選択モード.MouseClick( e );
1868 this.編集モード.MouseClick( e );
1871 protected void pictureBox譜面パネル_MouseDown( object sender, MouseEventArgs e )
1873 // 選択モードオブジェクトへ処理を引き継ぐ。
1875 this.選択モード.MouseDown( e );
1877 protected void pictureBox譜面パネル_MouseEnter( object sender, EventArgs e )
1879 // オートフォーカスが有効の場合、譜面にマウスが入ったら譜面がフォーカスを得る。"
1880 if( this.Config.AutoFocus )
1881 this.pictureBox譜面パネル.Focus();
1883 protected void pictureBox譜面パネル_MouseLeave( object sender, EventArgs e )
1885 // 編集モードオブジェクトへ処理を引き継ぐ。
1887 this.編集モード.MouseLeave( e );
1889 protected void pictureBox譜面パネル_MouseMove( object sender, MouseEventArgs e )
1891 // 選択・編集モードオブジェクトのいずれかへ処理を引き継ぐ。
1894 this.選択モード.MouseMove( e );
1898 this.編集モード.MouseMove( e );
1901 protected void pictureBox譜面パネル_Paint( object sender, PaintEventArgs e )
1903 if( false == this.初期化完了 )
1904 return; // 初期化が終わってないのに呼び出されることがあるので、その場合は無視。
1906 #region " 小節数が変わってたら、スクロールバーの値域を調整する。"
1908 int 全譜面の高さgrid = this.譜面.全小節の高さgrid;
1910 if( this.vScrollBar譜面用垂直スクロールバー.Maximum != 全譜面の高さgrid - 1 ) // 小節数が変わっている
1912 // 譜面の高さ(grid)がどれだけ変わったか?
1913 int 増加分grid = ( 全譜面の高さgrid - 1 ) - this.vScrollBar譜面用垂直スクロールバー.Maximum;
1915 #region " スクロールバーの状態を新しい譜面の高さに合わせる。"
1918 int value = this.vScrollBar譜面用垂直スクロールバー.Value; // 次の式で Maximum が Value より小さくなると例外が発生するので、
1919 this.vScrollBar譜面用垂直スクロールバー.Value = 0; // Value のバックアップを取っておいて、ひとまず 0 にする。
1920 this.vScrollBar譜面用垂直スクロールバー.Maximum = 全譜面の高さgrid - 1;
1922 int newValue = value + 増加分grid;
1924 // オーバーフローしないようクリッピングする。
1927 this.vScrollBar譜面用垂直スクロールバー.Value = 0;
1929 else if( ( this.vScrollBar譜面用垂直スクロールバー.Maximum - this.vScrollBar譜面用垂直スクロールバー.LargeChange ) <= newValue )
1931 this.vScrollBar譜面用垂直スクロールバー.Value = this.vScrollBar譜面用垂直スクロールバー.Maximum - this.vScrollBar譜面用垂直スクロールバー.LargeChange;
1935 this.vScrollBar譜面用垂直スクロールバー.Value = newValue;
1940 #region " 譜面表示下辺の位置を更新する。"
1942 this.譜面.現在の譜面表示下辺の譜面内絶対位置grid =
1943 ( ( this.vScrollBar譜面用垂直スクロールバー.Maximum - this.vScrollBar譜面用垂直スクロールバー.LargeChange ) + 1 ) - this.vScrollBar譜面用垂直スクロールバー.Value;
1951 this.譜面.描画する( e.Graphics, this.pictureBox譜面パネル );
1955 // 選択・編集モードオブジェクトのいずれかへ処理を引き継ぐ。
1958 this.選択モード.Paint( e );
1962 this.編集モード.Paint( e );
1965 protected void pictureBox譜面パネル_PreviewKeyDown( object sender, PreviewKeyDownEventArgs e )
1967 if( Keys.Prior == e.KeyCode )
1969 #region " PageUp → 移動量に対応する grid だけ垂直つまみを移動させる。あとはこの移動で生じる ChangedValue イベントで処理。"
1971 int 移動すべき数grid = -this.GRID_PER_PART;
1972 int 新しい位置 = this.vScrollBar譜面用垂直スクロールバー.Value + 移動すべき数grid;
1973 int 最小値 = this.vScrollBar譜面用垂直スクロールバー.Minimum;
1974 int 最大値 = ( this.vScrollBar譜面用垂直スクロールバー.Maximum + 1 ) - this.vScrollBar譜面用垂直スクロールバー.LargeChange;
1980 else if( 新しい位置 > 最大値 )
1984 this.vScrollBar譜面用垂直スクロールバー.Value = 新しい位置;
1988 else if( Keys.Next == e.KeyCode )
1990 #region " PageDown → 移動量に対応する grid だけ垂直つまみを移動させる。あとはこの移動で生じる ChangedValue イベントで処理。"
1992 int 移動すべき数grid = this.GRID_PER_PART;
1993 int 新しい位置 = this.vScrollBar譜面用垂直スクロールバー.Value + 移動すべき数grid;
1994 int 最小値 = this.vScrollBar譜面用垂直スクロールバー.Minimum;
1995 int 最大値 = ( this.vScrollBar譜面用垂直スクロールバー.Maximum + 1 ) - this.vScrollBar譜面用垂直スクロールバー.LargeChange;
2001 else if( 新しい位置 > 最大値 )
2005 this.vScrollBar譜面用垂直スクロールバー.Value = 新しい位置;
2011 // 編集モードオブジェクトへ処理を引き継ぐ。
2013 this.編集モード.PreviewKeyDown( e );
2017 protected void splitContainer分割パネルコンテナ_MouseWheel( object sender, MouseEventArgs e )
2019 if( false == this.初期化完了 )
2020 return; // 初期化が終わってないのに呼び出されることがあるので、その場合は無視。
2022 #region " 移動量に対応する grid だけ垂直つまみを移動させる。あとはこの移動で生じる ChangedValue イベントで処理する。"
2027 // e.Delta は、スクロールバーを下へ動かしたいときに負、上へ動かしたいときに正となる。
2028 int 移動すべき行数 = ( -e.Delta * SystemInformation.MouseWheelScrollLines ) / 120;
2031 int 移動すべき数grid = 移動すべき行数 * ( this.GRID_PER_PART / 4 );
2033 // スクロールバーのつまみを移動する。
2034 int 新しい位置 = this.vScrollBar譜面用垂直スクロールバー.Value + 移動すべき数grid;
2035 int 最小値 = this.vScrollBar譜面用垂直スクロールバー.Minimum;
2036 int 最大値 = ( this.vScrollBar譜面用垂直スクロールバー.Maximum + 1 ) - this.vScrollBar譜面用垂直スクロールバー.LargeChange;
2042 else if( 新しい位置 > 最大値 )
2046 this.vScrollBar譜面用垂直スクロールバー.Value = 新しい位置;
2050 protected void splitContainer分割パネルコンテナ_Panel2_SizeChanged( object sender, EventArgs e )
2052 if( false == this.初期化完了 )
2053 return; // 初期化が終わってないのに呼び出されることがあるので、その場合は無視。
2055 this.垂直スクロールバーと譜面の上下位置を調整する();
2057 protected void splitContainer分割パネルコンテナ_Panel2_Paint( object sender, PaintEventArgs e )
2059 if( false == this.初期化完了 )
2060 return; // 初期化が終わってないのに呼び出されることがあるので、その場合は無視。
2063 var メモ領域左上隅の位置 = new PointF() {
2064 X = this.譜面.レーンの合計幅px,
2065 Y = this.pictureBox譜面パネル.Location.Y,
2068 #region " 見出し<小節メモ>を描画する。"
2070 g.DrawString( Properties.Resources.MSG_小節メモ, this.メモ用フォント, Brushes.White, PointF.Add( メモ領域左上隅の位置, new Size( 24, -24 )/*マージン*/ ) );
2073 #region " 小節メモを描画する。"
2076 // グリッド値は 上辺>下辺 なので注意。
2077 int パネル下辺grid = this.譜面.現在の譜面表示下辺の譜面内絶対位置grid;
2078 int パネル上辺grid = パネル下辺grid + ( this.pictureBox譜面パネル.ClientSize.Height * this.GRID_PER_PIXEL );
2079 int 開始小節番号 = this.譜面.現在譜面表示下辺に存在している小節番号;
2081 for( int 小節番号 = 開始小節番号; 小節番号 <= this.譜面.SSTFormatScore.最大小節番号; 小節番号++ )
2083 int 小節の下辺grid = this.譜面.小節先頭の譜面内絶対位置gridを返す( 小節番号 );
2084 int 小節の上辺grid = 小節の下辺grid + this.譜面.小節長をグリッドで返す( 小節番号 );
2086 if( 小節の下辺grid > パネル上辺grid )
2087 break; // 小節が画面上方にはみ出し切ってしまったらそこで終了。
2089 if( this.譜面.SSTFormatScore.dicメモ.ContainsKey( 小節番号 ) )
2091 string メモ = this.譜面.SSTFormatScore.dicメモ[ 小節番号 ];
2093 string[] lines = メモ.Split( new string[] { Environment.NewLine }, StringSplitOptions.None );
2094 int 行数 = lines.Length;
2096 var メモの位置 = new PointF() {
2097 X = メモ領域左上隅の位置.X + 4, // + 4 はマージン
2098 Y = メモ領域左上隅の位置.Y + ( パネル上辺grid - 小節の下辺grid ) / this.GRID_PER_PIXEL - ( 行数 * 16 ), // 9pt = だいたい16px
2100 g.DrawString( メモ, this.メモ用フォント, Brushes.White, メモの位置 );
2107 protected void vScrollBar譜面用垂直スクロールバー_ValueChanged( object sender, EventArgs e )
2109 if( false == this.初期化完了 )
2110 return; // 初期化が終わってないのに呼び出されることがあるので、その場合は無視。
2112 var bar = vScrollBar譜面用垂直スクロールバー;
2117 this.譜面.現在の譜面表示下辺の譜面内絶対位置grid = ( ( bar.Maximum + 1 ) - bar.LargeChange ) - bar.Value;
2119 // 編集モードの場合、カーソルのgrid位置を再計算。
2122 this.編集モード.MouseMove(
2123 new MouseEventArgs( MouseButtons.None, 0, this.編集モード.現在のチップカーソル領域.X, this.編集モード.現在のチップカーソル領域.Y, 0 ) );
2127 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2128 this.numericUpDownメモ用小節番号.Value = this.譜面.現在カレントラインに存在している小節番号;
2129 this.次のプロパティ変更がUndoRedoリストに載るようにする();
2132 this.splitContainer分割パネルコンテナ.Panel2.Refresh();
2139 protected void toolStripMenuItem選択チップの切り取り_Click( object sender, EventArgs e )
2143 protected void toolStripMenuItem選択チップのコピー_Click( object sender, EventArgs e )
2147 protected void toolStripMenuItem選択チップの貼り付け_Click( object sender, EventArgs e )
2149 // メニューが開かれたときのマウスの座標を取得。
2150 // ※メニューは必ずマウス位置を左上にして表示されるとは限らないため、メニューの表示位置からは取得しないこと。
2151 var マウスの位置 = this.選択モードのコンテクストメニューを開いたときのマウスの位置;
2153 if( this.譜面.譜面パネル内X座標pxにある編集レーンを返す( マウスの位置.X ) == 編集レーン種別.Unknown )
2154 return; // クリックされた場所にレーンがないなら無視。
2157 this.Act貼り付ける( this.譜面.譜面パネル内Y座標pxにおける譜面内絶対位置gridをガイド幅単位で返す( マウスの位置.Y ) );
2159 protected void toolStripMenuItem選択チップの削除_Click( object sender, EventArgs e )
2163 protected void toolStripMenuItemすべてのチップの選択_Click( object sender, EventArgs e )
2165 // 編集モードなら強制的に選択モードにする。
2167 this.選択モードに切替えて関連GUIを設定する();
2170 this.選択モード.全チップを選択する();
2172 protected void toolStripMenuItem小節長変更_Click( object sender, EventArgs e )
2174 // メニューが開かれたときのマウスの座標を取得。
2175 // ※メニューは必ずマウス位置を左上にして表示されるとは限らないため、メニューの表示位置からは取得しないこと。
2176 var マウスの位置 = this.選択モードのコンテクストメニューを開いたときのマウスの位置;
2178 if( this.譜面.譜面パネル内X座標pxにある編集レーンを返す( マウスの位置.X ) == 編集レーン種別.Unknown )
2179 return; // クリックされた場所にレーンがないなら無視。
2182 this.Act小節長倍率を変更する( this.譜面.譜面パネル内Y座標pxにおける小節番号を返す( マウスの位置.Y ) );
2184 protected void toolStripMenuItem小節の挿入_Click( object sender, EventArgs e )
2186 // メニューが開かれたときのマウスの座標を取得。
2187 // ※メニューは必ずマウス位置を左上にして表示されるとは限らないため、メニューの表示位置からは取得しないこと。
2188 var マウスの位置 = this.選択モードのコンテクストメニューを開いたときのマウスの位置;
2190 if( this.譜面.譜面パネル内X座標pxにある編集レーンを返す( マウスの位置.X ) == 編集レーン種別.Unknown )
2191 return; // クリックされた場所にレーンがないなら無視。
2194 this.Act小節を挿入する( this.譜面.譜面パネル内Y座標pxにおける小節番号を返す( マウスの位置.Y ) );
2196 protected void toolStripMenuItem小節の削除_Click( object sender, EventArgs e )
2198 // メニューが開かれたときのマウスの座標を取得。
2199 // ※メニューは必ずマウス位置を左上にして表示されるとは限らないため、メニューの表示位置からは取得しないこと。
2200 var マウスの位置 = this.選択モードのコンテクストメニューを開いたときのマウスの位置;
2202 if( this.譜面.譜面パネル内X座標pxにある編集レーンを返す( マウスの位置.X ) == 編集レーン種別.Unknown )
2203 return; // クリックされた場所にレーンがないなら無視。
2206 this.Act小節を削除する( this.譜面.譜面パネル内Y座標pxにおける小節番号を返す( マウスの位置.Y ) );
2212 protected void textBox曲名_TextChanged( object sender, EventArgs e )
2214 #region " この変更が Undo/Redo したことによるものではない場合、UndoRedoセルを追加 or 修正する。"
2216 if( false == UndoRedo.管理.UndoRedoした直後である )
2219 var cell = this.UndoRedo管理.Undoするセルを取得して返す_見るだけ();
2221 if( ( null != cell ) && cell.所有権がある( this.textBox曲名 ) )
2223 // (A) 所有者である → 最新のセルの "変更後の値" を現在のコントロールの値に更新する。
2224 ( (UndoRedo.セル<string>) cell ).変更後の値 = this.textBox曲名.Text;
2228 // (B) 所有者ではない → 以下のようにセルを新規追加する。
2231 // "所有者ID" ← 対象となるコンポーネントオブジェクト
2232 var cc = new UndoRedo.セル<string>(
2233 所有者ID: this.textBox曲名,
2234 Undoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
2235 this.タブを選択する( タブ種別.基本情報 );
2236 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2237 this.textBox曲名.Text = 変更前;
2238 this.textBox曲名.Focus();
2240 Redoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
2241 this.タブを選択する( タブ種別.基本情報 );
2242 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2243 this.textBox曲名.Text = 変更後;
2244 this.textBox曲名.Focus();
2247 変更前の値: this.textBox曲名_以前の値,
2248 変更後の値: this.textBox曲名.Text,
2252 this.UndoRedo管理.セルを追加する( cc );
2255 this.UndoRedo用GUIのEnabledを設定する();
2261 this.textBox曲名_以前の値 = this.textBox曲名.Text; // 以前の値 ← 現在の値
2262 UndoRedo.管理.UndoRedoした直後である = false;
2266 譜面.SSTFormatScore.Header.曲名 = this.textBox曲名.Text;
2268 protected void textBox曲名_Leave( object sender, EventArgs e )
2270 // 最新の UndoRedoセル の所有権を放棄する。
2271 this.UndoRedo管理.Undoするセルを取得して返す_見るだけ()?.所有権を放棄する( this.textBox曲名 );
2273 protected string textBox曲名_以前の値 = "";
2275 protected void textBox説明_TextChanged( object sender, EventArgs e )
2277 #region " この変更が Undo/Redo したことによるものではない場合、UndoRedoセルを追加 or 修正する。"
2279 if( false == UndoRedo.管理.UndoRedoした直後である )
2282 var cell = this.UndoRedo管理.Undoするセルを取得して返す_見るだけ();
2283 if( ( null != cell ) && cell.所有権がある( this.textBox説明 ) )
2285 // (A) 所有者である → 最新のセルの "変更後の値" を現在のコントロールの値に更新。
2287 ( (UndoRedo.セル<string>) cell ).変更後の値 = this.textBox説明.Text;
2291 // (B) 所有者ではない → 以下のようにセルを新規追加する。
2294 // "所有者ID" ← 対象となるコンポーネントオブジェクト
2295 var cc = new UndoRedo.セル<string>(
2296 所有者ID: this.textBox説明,
2297 Undoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
2298 this.タブを選択する( タブ種別.基本情報 );
2299 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2300 this.textBox説明.Text = 変更前;
2301 this.textBox説明.Focus();
2303 Redoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
2304 this.タブを選択する( タブ種別.基本情報 );
2305 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2306 this.textBox説明.Text = 変更後;
2307 this.textBox説明.Focus();
2310 変更前の値: this.textBox説明_以前の値,
2311 変更後の値: this.textBox説明.Text,
2315 this.UndoRedo管理.セルを追加する( cc );
2318 this.UndoRedo用GUIのEnabledを設定する();
2324 this.textBox説明_以前の値 = this.textBox説明.Text; // 以前の値 ← 現在の値
2325 UndoRedo.管理.UndoRedoした直後である = false;
2329 譜面.SSTFormatScore.Header.説明文 = this.textBox説明.Text;
2331 protected void textBox説明_Leave( object sender, EventArgs e )
2333 // 最新 UndoRedoセル の所有権を放棄する。
2334 this.UndoRedo管理.Undoするセルを取得して返す_見るだけ()?.所有権を放棄する( this.textBox説明 );
2336 protected string textBox説明_以前の値 = "";
2338 protected void textBoxメモ_TextChanged( object sender, EventArgs e )
2340 #region " この変更が Undo/Redo したことによるものではない場合、UndoRedoセルを追加or修正する。"
2342 if( !UndoRedo.管理.UndoRedoした直後である )
2346 UndoRedo.セルBase cell = this.UndoRedo管理.Undoするセルを取得して返す_見るだけ();
2348 if( ( cell != null ) && cell.所有権がある( this.textBoxメモ ) )
2350 // (Yes) 最新のセルの "変更後の値" を <現在の値> に更新。
2352 ( (UndoRedo.セル<string>) cell ).変更後の値 = this.textBoxメモ.Text;
2359 // "所有者ID" = 対象となるコンポーネントオブジェクト
2361 var cc = new UndoRedo.セル<string>(
2362 所有者ID: this.textBoxメモ,
2363 Undoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
2364 this.タブを選択する( タブ種別.基本情報 );
2365 this.numericUpDownメモ用小節番号.Value = (decimal) 任意1;
2366 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2367 this.textBoxメモ.Text = 変更前;
2368 this.textBoxメモ.Focus();
2370 int 小節番号 = (int) ( (decimal) 任意1 );
2372 #region " dicメモ の更新 "
2374 if( this.譜面.SSTFormatScore.dicメモ.ContainsKey( 小節番号 ) )
2376 if( string.IsNullOrEmpty( 変更前 ) )
2377 this.譜面.SSTFormatScore.dicメモ.Remove( 小節番号 );
2379 this.譜面.SSTFormatScore.dicメモ[ 小節番号 ] = 変更前;
2383 if( !string.IsNullOrEmpty( 変更前 ) )
2384 this.譜面.SSTFormatScore.dicメモ.Add( 小節番号, 変更前 );
2389 this.Act小節の先頭へ移動する( 小節番号 );
2390 this.splitContainer分割パネルコンテナ.Panel2.Refresh(); // 小節メモをリフレッシュ。
2392 Redoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
2393 this.タブを選択する( タブ種別.基本情報 );
2394 this.numericUpDownメモ用小節番号.Value = (decimal) 任意1;
2395 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2396 this.textBoxメモ.Text = 変更後;
2397 this.textBoxメモ.Focus();
2399 int 小節番号 = (int) ( (decimal) 任意1 );
2401 #region " dicメモの更新 "
2403 if( this.譜面.SSTFormatScore.dicメモ.ContainsKey( 小節番号 ) )
2405 if( string.IsNullOrEmpty( 変更後 ) )
2406 this.譜面.SSTFormatScore.dicメモ.Remove( 小節番号 );
2408 this.譜面.SSTFormatScore.dicメモ[ 小節番号 ] = 変更後;
2412 if( !string.IsNullOrEmpty( 変更後 ) )
2413 this.譜面.SSTFormatScore.dicメモ.Add( 小節番号, 変更後 );
2418 this.Act小節の先頭へ移動する( 小節番号 );
2419 this.splitContainer分割パネルコンテナ.Panel2.Refresh(); // 小節メモをリフレッシュ。
2422 変更前の値: this.textBoxメモ_以前の値,
2423 変更後の値: this.textBoxメモ.Text,
2424 任意1: (object) this.numericUpDownメモ用小節番号.Value,
2427 this.UndoRedo管理.セルを追加する( cc );
2430 this.UndoRedo用GUIのEnabledを設定する();
2436 this.textBoxメモ_以前の値 = this.textBoxメモ.Text; // <以前の値> = <現在の値>
2438 if( false == UndoRedo.管理.UndoRedoした直後である )
2441 UndoRedo.管理.UndoRedoした直後である = false;
2443 #region " 小節番号に対応するメモを dicメモ に登録する。"
2446 int 小節番号 = (int) this.numericUpDownメモ用小節番号.Value;
2448 if( string.IsNullOrEmpty( this.textBoxメモ.Text ) )
2451 if( this.譜面.SSTFormatScore.dicメモ.ContainsKey( 小節番号 ) )
2452 this.譜面.SSTFormatScore.dicメモ.Remove( 小節番号 ); // 存在してたら削除。
2458 if( this.譜面.SSTFormatScore.dicメモ.ContainsKey( 小節番号 ) )
2459 this.譜面.SSTFormatScore.dicメモ[ 小節番号 ] = this.textBoxメモ.Text; // 存在してたら更新。
2461 this.譜面.SSTFormatScore.dicメモ.Add( 小節番号, this.textBoxメモ.Text ); // 存在してなかったら追加。
2466 #region " もし最終小節だったなら、後ろに4つ小節を加える。"
2469 int 小節番号 = (int) this.numericUpDownメモ用小節番号.Value;
2470 if( 小節番号 == this.譜面.SSTFormatScore.最大小節番号 )
2472 this.譜面.最後の小節の後ろに小節を4つ追加する();
2478 protected void textBoxメモ_Leave( object sender, EventArgs e )
2480 // 最新 UndoRedoセル の所有権を放棄する。
2481 this.UndoRedo管理.Undoするセルを取得して返す_見るだけ()?.所有権を放棄する( this.textBoxメモ );
2484 this.splitContainer分割パネルコンテナ.Panel2.Refresh();
2486 protected string textBoxメモ_以前の値 = "";
2488 protected void numericUpDownメモ用小節番号_ValueChanged( object sender, EventArgs e )
2490 // 小節番号にあわせて、textBoxメモにメモを表示する。
2491 int 小節番号 = (int) this.numericUpDownメモ用小節番号.Value;
2492 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2493 if( this.譜面.SSTFormatScore.dicメモ.ContainsKey( 小節番号 ) )
2494 this.textBoxメモ.Text = this.譜面.SSTFormatScore.dicメモ[ 小節番号 ];
2496 this.textBoxメモ.Text = "";
2497 this.次のプロパティ変更がUndoRedoリストに載るようにする();
2502 private Font メモ用フォント = new Font( FontFamily.GenericSansSerif, 9.0f );
2503 private readonly Dictionary<int, string> dic音量ラベル = new Dictionary<int, string>() {
2504 { 1, "1 (Smallest)" },
2505 { 2, "2 (Smaller)" },
2506 { 3, "3 (Middle)" },
2507 { 4, "4 (Normal)" },