2 using System.Collections.Generic;
3 using System.Diagnostics;
8 using System.Reflection;
9 using System.ServiceModel;
10 using System.ServiceModel.Channels;
11 using System.Text.RegularExpressions;
12 using System.Windows.Forms;
13 using FDK; // for string拡張
17 partial class メインフォーム : Form
19 public int メジャーバージョン番号 => ( Assembly.GetExecutingAssembly().GetName().Version.Major );
20 public int マイナーバージョン番号 => ( Assembly.GetExecutingAssembly().GetName().Version.Minor );
21 public int リビジョン番号 => ( Assembly.GetExecutingAssembly().GetName().Version.Revision );
22 public int ビルド番号 => ( Assembly.GetExecutingAssembly().GetName().Version.Build );
24 public const int 最大音量 = 4;
25 public const int 最小音量 = 1;
31 return this.bs_未保存である;
36 this.bs_未保存である = value;
38 // ウィンドウのタイトルバーの文字列を修正する。
39 string 表示するファイルの名前 = ( string.IsNullOrEmpty( this.編集中のファイル名 ) ) ? Properties.Resources.NEW_FILENAME : this.編集中のファイル名;
42 // 変更ありかつ未保存なら「*」を付ける。
43 this.Text = $"SSTFEditor {this.メジャーバージョン番号}.{this.マイナーバージョン番号}.{this.リビジョン番号}.{this.ビルド番号} *[{表示するファイルの名前}]";
44 this.toolStripMenuItem上書き保存.Enabled = true;
45 this.toolStripButton上書き保存.Enabled = true;
49 // 保存後変更がないなら「*」は付けない。
50 this.Text = $"SSTFEditor {this.メジャーバージョン番号}.{this.マイナーバージョン番号}.{this.リビジョン番号}.{this.ビルド番号} [{表示するファイルの名前}]";
51 this.toolStripMenuItem上書き保存.Enabled = false;
52 this.toolStripButton上書き保存.Enabled = false;
56 public bool 選択モードである => ( ( CheckState.Checked == this.toolStripButton選択モード.CheckState ) ? true : false );
57 public bool 編集モードである => ( ( CheckState.Checked == this.toolStripButton編集モード.CheckState ) ? true : false );
59 public int GRID_PER_PART { get; protected set; }
60 public int GRID_PER_PIXEL => ( this.bs_GRID_PER_PIXEL / ( this.toolStripComboBox譜面拡大率.SelectedIndex + 1 ) );
62 public bool 初期化完了 = false;
67 public UndoRedo.管理 UndoRedo管理;
68 public クリップボード クリップボード;
69 public Size 譜面パネルサイズ => ( this.pictureBox譜面パネル.ClientSize );
70 public SSTFormat.チップ種別 現在のチップ種別
74 return this.bs_e現在のチップ種別;
78 this.bs_e現在のチップ種別 = value;
79 this.label現在のチップ種別.Text = this.チップ種別toチップ名対応表[ value ];
82 public int 現在のチップ音量 = メインフォーム.最大音量;
86 InitializeComponent();
91 public void 選択モードに切替えて関連GUIを設定する()
93 this.toolStripButton選択モード.CheckState = CheckState.Checked;
94 this.toolStripButton編集モード.CheckState = CheckState.Unchecked;
96 this.toolStripMenuItem選択モード.CheckState = CheckState.Checked;
97 this.toolStripMenuItem編集モード.CheckState = CheckState.Unchecked;
99 this.label現在のチップ種別.Text = "----";
103 public void 編集モードに切替えて関連GUIを設定する()
105 this.選択モード.全チップの選択を解除する();
108 this.toolStripButton選択モード.CheckState = CheckState.Unchecked;
109 this.toolStripButton編集モード.CheckState = CheckState.Checked;
111 this.toolStripMenuItem選択モード.CheckState = CheckState.Unchecked;
112 this.toolStripMenuItem編集モード.CheckState = CheckState.Checked;
114 public void 選択チップの有無に応じて編集用GUIのEnabledを設定する()
116 bool 譜面上に選択チップがある = this.選択チップが1個以上ある;
117 bool クリップボードに選択チップがある = ( null != this.クリップボード ) && ( 0 < this.クリップボード.セル数 );
119 // 編集メニューの Enabled 設定
120 this.toolStripMenuItemコピー.Enabled = 譜面上に選択チップがある;
121 this.toolStripMenuItem切り取り.Enabled = 譜面上に選択チップがある;
122 this.toolStripMenuItem貼り付け.Enabled = クリップボードに選択チップがある;
123 this.toolStripMenuItem削除.Enabled = 譜面上に選択チップがある;
126 this.toolStripButtonコピー.Enabled = 譜面上に選択チップがある;
127 this.toolStripButton切り取り.Enabled = 譜面上に選択チップがある;
128 this.toolStripButton貼り付け.Enabled = クリップボードに選択チップがある;
129 this.toolStripButton削除.Enabled = 譜面上に選択チップがある;
132 this.toolStripMenuItem選択チップのコピー.Enabled = 譜面上に選択チップがある;
133 this.toolStripMenuItem選択チップの切り取り.Enabled = 譜面上に選択チップがある;
134 this.toolStripMenuItem選択チップの貼り付け.Enabled = クリップボードに選択チップがある;
135 this.toolStripMenuItem選択チップの削除.Enabled = 譜面上に選択チップがある;
137 public void 譜面をリフレッシュする()
139 this.pictureBox譜面パネル.Refresh();
141 public void UndoRedo用GUIのEnabledを設定する()
143 bool Undo可 = ( 0 < this.UndoRedo管理.Undo可能な回数 ) ? true : false;
144 bool Redo可 = ( 0 < this.UndoRedo管理.Redo可能な回数 ) ? true : false;
146 this.toolStripMenuItem元に戻す.Enabled = Undo可;
147 this.toolStripMenuItemやり直す.Enabled = Redo可;
148 this.toolStripButton元に戻す.Enabled = Undo可;
149 this.toolStripButtonやり直す.Enabled = Redo可;
151 public void 選択モードのコンテクストメニューを表示する( int x, int y )
153 this.contextMenuStrip譜面右メニュー.Show( this.pictureBox譜面パネル, x, y );
155 // メニューを表示した時のマウス座標を控えておく。
156 this.選択モードのコンテクストメニューを開いたときのマウスの位置 = new Point( x, y );
158 public void 譜面を縦スクロールする( int nスクロール量grid )
160 int 現在の位置grid = this.vScrollBar譜面用垂直スクロールバー.Value;
161 int スクロール後の位置grid = this.vScrollBar譜面用垂直スクロールバー.Value + nスクロール量grid;
162 int 最小値grid = this.vScrollBar譜面用垂直スクロールバー.Minimum;
163 int 最大値grid = ( this.vScrollBar譜面用垂直スクロールバー.Maximum + 1 ) - this.vScrollBar譜面用垂直スクロールバー.LargeChange;
165 if( スクロール後の位置grid < 最小値grid )
167 スクロール後の位置grid = 最小値grid;
169 else if( スクロール後の位置grid > 最大値grid )
171 スクロール後の位置grid = 最大値grid;
174 this.vScrollBar譜面用垂直スクロールバー.Value = スクロール後の位置grid;
177 protected readonly Dictionary<SSTFormat.チップ種別, string> チップ種別toチップ名対応表 = new Dictionary<SSTFormat.チップ種別, string>() {
180 { SSTFormat.チップ種別.Bass, "BassDrum" },
181 { SSTFormat.チップ種別.BPM, "BPM" },
182 { SSTFormat.チップ種別.China, "China" },
183 { SSTFormat.チップ種別.HiHat_Close, "HiHat(Close)" },
184 { SSTFormat.チップ種別.HiHat_Foot, "FootPedal" },
185 { SSTFormat.チップ種別.HiHat_HalfOpen, "HiHat(HarfOpen)" },
186 { SSTFormat.チップ種別.HiHat_Open, "HiHat(Open)" },
187 { SSTFormat.チップ種別.LeftCrash, "Crash" },
188 { SSTFormat.チップ種別.Ride, "Ride" },
189 { SSTFormat.チップ種別.Ride_Cup, "Ride(Cup)" },
190 { SSTFormat.チップ種別.RightCrash, "Crash" },
191 { SSTFormat.チップ種別.Snare, "Snare" },
192 { SSTFormat.チップ種別.Snare_ClosedRim, "Snare(CloseRimShot)" },
193 { SSTFormat.チップ種別.Snare_Ghost, "Snare(Ghost)" },
194 { SSTFormat.チップ種別.Snare_OpenRim, "Snare(OpenRimShot)" },
195 { SSTFormat.チップ種別.Splash, "Splash" },
196 { SSTFormat.チップ種別.Tom1, "HighTom" },
197 { SSTFormat.チップ種別.Tom1_Rim, "HighTom(RimShot)" },
198 { SSTFormat.チップ種別.Tom2, "LowTom" },
199 { SSTFormat.チップ種別.Tom2_Rim, "LowTom(RimShot)" },
200 { SSTFormat.チップ種別.Tom3, "FloorTom" },
201 { SSTFormat.チップ種別.Tom3_Rim, "FloorTom(RimShot)" },
202 { SSTFormat.チップ種別.Unknown, "" },
203 { SSTFormat.チップ種別.小節線, "" },
204 { SSTFormat.チップ種別.背景動画, "" },
205 { SSTFormat.チップ種別.拍線, "" },
206 { SSTFormat.チップ種別.小節メモ, "" },
210 protected bool 選択チップが1個以上ある
214 if( ( null != this.譜面.SSTFormatScore ) &&
215 ( null != this.譜面.SSTFormatScore.チップリスト ) &&
216 ( 0 < this.譜面.SSTFormatScore.チップリスト.Count ) )
218 foreach( var chip in this.譜面.SSTFormatScore.チップリスト )
227 protected int 現在のガイド間隔 = 0;
228 protected Point 選択モードのコンテクストメニューを開いたときのマウスの位置;
230 protected ChannelFactory<SST.IStrokeStyleTService> SSTファクトリ = null;
231 protected SST.IStrokeStyleTService SSTサービス = null;
233 private bool bs_未保存である = false;
234 private SSTFormat.チップ種別 bs_e現在のチップ種別;
235 private int bs_GRID_PER_PIXEL = 1;
238 /// SSTFEditor.exe と StrokeStyleT.exe が格納されているフォルダへのパス。
240 protected string システムフォルダパス => ( Path.GetDirectoryName( Application.ExecutablePath ) );
242 /// Windowsログインユーザのアプリデータフォルダ。
246 /// 例: "C:\Users\ログインユーザ名\ApplicationData\SSTFEditor\"
248 protected string ユーザフォルダパス
252 var path = Path.Combine( Environment.GetFolderPath( Environment.SpecialFolder.ApplicationData, Environment.SpecialFolderOption.Create ), @"SSTFEditor\" );
254 if( false == Directory.Exists( path ) )
255 Directory.CreateDirectory( path ); // なければ作成する。
260 protected string 作業フォルダパス = null;
261 protected string 編集中のファイル名 = null;
262 protected string 最後にプレイヤーに渡した一時ファイル名 = null;
264 // アクションメソッド(機能ツリーの最上位。メニューやコマンドバーなどから呼び出される。)
266 protected void Actアプリを起動する()
268 this.GRID_PER_PART = int.Parse( Properties.Resources.GRID_PER_PART );
269 this.bs_GRID_PER_PIXEL = int.Parse( Properties.Resources.GRID_PER_PIXEL );
271 // 作業フォルダの初期値は、Windowsユーザのマイドキュメントフォルダ。
272 this.作業フォルダパス = Environment.GetFolderPath( Environment.SpecialFolder.MyDocuments );
275 this.Config = Config.読み込む( Path.Combine( this.ユーザフォルダパス, Properties.Resources.CONFIG_FILE_NAME ) );
276 if( this.Config.ViewerPath.Nullまたは空である() )
278 // 既定のプレイヤーは、exe と同じ場所にあるものとする。
279 this.Config.ViewerPath = Path.Combine( this.システムフォルダパス, Properties.Resources.PLAYER_NAME );
281 if( false == File.Exists( this.Config.ViewerPath ) )
282 this.Config.ViewerPath = ""; // ビュアーが存在してない。
285 // デザイナでは追加できないイベントを手動で追加する。
286 this.splitContainer分割パネルコンテナ.MouseWheel += new MouseEventHandler( splitContainer分割パネルコンテナ_MouseWheel );
289 this.ConfigのRecentUsedFilesをファイルメニューへ追加する();
293 this.Actガイド間隔を変更する( 16 ); // 初期は 1/16 間隔。
294 this.Act譜面拡大率を変更する( 1 ); // 初期は 標準。
299 protected void Actアプリを終了する()
302 this.SSTサービス = null; // サービスは解放処理なし
305 this.SSTファクトリ.Close();
307 catch( CommunicationException )
309 // すでに通信が閉じられている(SSTサービスホストが終了している)。
312 // 一時ファイルが残っていれば、削除する。
313 if( File.Exists( this.最後にプレイヤーに渡した一時ファイル名 ) )
314 File.Delete( this.最後にプレイヤーに渡した一時ファイル名 );
317 this.Config.保存する( Path.Combine( this.ユーザフォルダパス, Properties.Resources.CONFIG_FILE_NAME ) );
319 FDK.Utilities.解放する( ref this.譜面 );
320 FDK.Utilities.解放する( ref this.選択モード );
322 protected void Act新規作成する()
324 if( DialogResult.Cancel == this.未保存なら保存する() )
325 return; // 保存がキャンセルされた場合はここで中断。
329 protected void Act開く()
331 if( DialogResult.Cancel == this.未保存なら保存する() )
332 return; // 保存がキャンセルされた場合はここで中断。
334 #region " [ファイルを開く] ダイアログでファイルを選択する。"
336 var dialog = new OpenFileDialog() {
337 Title = Properties.Resources.MSG_ファイル選択ダイアログのタイトル,
338 Filter = Properties.Resources.MSG_曲ファイル選択ダイアログのフィルタ,
340 InitialDirectory = this.作業フォルダパス,
342 var result = dialog.ShowDialog( this );
344 // メインフォームを再描画してダイアログを完全に消す。
348 if( DialogResult.OK != result )
353 this.ファイルを読み込む( dialog.FileName );
355 protected void Act指定されたファイルを開く( string ファイルパス )
357 if( DialogResult.Cancel == this.未保存なら保存する() )
358 return; // 保存がキャンセルされた場合はここで中断。
360 this.ファイルを読み込む( ファイルパス );
362 protected void Act上書き保存する()
364 if( string.IsNullOrEmpty( this.編集中のファイル名 ) )
366 #region " ファイル名が未設定なら、初めての保存と見なし、ファイル保存ダイアログで保存ファイル名を指定させる。"
368 string 絶対パスファイル名 = this.ファイル保存ダイアログを開いてファイル名を取得する();
370 if( string.IsNullOrEmpty( 絶対パスファイル名 ) )
371 return; // ファイル保存ダイアログがキャンセルされたのならここで打ち切り。
373 this.作業フォルダパス = Path.GetDirectoryName( 絶対パスファイル名 ); // ダイアログでディレクトリを変更した場合、カレントディレクトリも変更されている。
374 this.編集中のファイル名 = Path.GetFileName( 絶対パスファイル名 );
380 Path.Combine( this.作業フォルダパス, this.編集中のファイル名 ),
383 protected void Act上書き保存する( string ファイルの絶対パス, bool 一時ファイルである )
385 #region " [保存中です] ポップアップを表示する。"
387 var msg = new Popupメッセージ(
388 Properties.Resources.MSG_保存中です + Environment.NewLine +
389 Properties.Resources.MSG_しばらくお待ち下さい );
398 #region " 選択モードだったら、全チップの選択を解除する。"
401 this.選択モード.全チップの選択を解除する();
404 #region " 出力するパス内の背景動画を検索する。"
406 this.textBox背景動画.Text =
407 ( from ファイル名 in Directory.GetFiles( Path.GetDirectoryName( ファイルの絶対パス ) )
408 where SSTFormat.スコア.背景動画のデフォルト拡張子s.Any( 拡張子名 => ( Path.GetExtension( ファイル名 ).ToLower() == 拡張子名 ) )
409 select ファイル名 ).FirstOrDefault(); // 複数あったら、最初に見つけたほうを採用。1つも見つからなければ null。
412 #region " SSTFファイルを出力する。"
414 this.譜面.SSTFファイルを書き出す(
416 $"# Created by SSTFEditor {this.メジャーバージョン番号}.{this.マイナーバージョン番号}.{this.リビジョン番号}.{this.ビルド番号}" );
419 #region " 出力したファイルのパスを、[ファイル]メニューの最近使ったファイル一覧に追加する。"
421 if( false == 一時ファイルである )
423 this.Config.ファイルを最近使ったファイルの一覧に追加する( ファイルの絶対パス );
424 this.ConfigのRecentUsedFilesをファイルメニューへ追加する();
431 #region " [保存中です] ポップアップを閉じる。"
437 // 最後に、ダイアログのゴミなどを消すために再描画。
440 if( false == 一時ファイルである )
444 protected void Act名前を付けて保存する()
446 #region " ユーザに保存ファイル名を入力させる。"
448 string 絶対パスファイル名 = this.ファイル保存ダイアログを開いてファイル名を取得する();
449 if( string.IsNullOrEmpty( 絶対パスファイル名 ) )
450 return; // キャンセルされたらここで中断。
452 this.作業フォルダパス = Path.GetDirectoryName( 絶対パスファイル名 );
453 this.編集中のファイル名 = Path.GetFileName( 絶対パスファイル名 );
459 this.未保存である = true; // ウィンドウタイトルに表示されているファイル名を変更するため、一度わざと true にする。
462 protected void Act終了する()
466 protected void Act元に戻す()
468 // Undo する対象を UndoRedoリストから取得する。
469 var cell = this.UndoRedo管理.Undoするセルを取得して返す();
477 this.UndoRedo用GUIのEnabledを設定する();
478 this.選択チップの有無に応じて編集用GUIのEnabledを設定する();
481 protected void Actやり直す()
483 // Redo する対象を UndoRedoリストから取得する。
484 var cell = this.UndoRedo管理.Redoするセルを取得して返す();
492 this.UndoRedo用GUIのEnabledを設定する();
493 this.選択チップの有無に応じて編集用GUIのEnabledを設定する();
496 protected void Act切り取る()
498 // 譜面にフォーカスがないなら、何もしない。
499 if( false == this.pictureBox譜面パネル.Focused )
506 protected void Actコピーする()
508 // 譜面にフォーカスがないなら何もしない。
509 if( false == this.pictureBox譜面パネル.Focused )
513 this.クリップボード.現在選択されているチップをボードにコピーする();
516 this.選択チップの有無に応じて編集用GUIのEnabledを設定する();
519 protected void Act貼り付ける( int 貼り付けを開始する譜面内絶対位置grid )
521 // 譜面にフォーカスがないなら何もしない。
522 if( false == this.pictureBox譜面パネル.Focused )
525 this.クリップボード.チップを指定位置から貼り付ける( 貼り付けを開始する譜面内絶対位置grid );
527 protected void Act削除する()
529 // 譜面にフォーカスがないなら何もしない。
530 if( false == this.pictureBox譜面パネル.Focused )
535 this.UndoRedo管理.トランザクション記録を開始する();
537 // 譜面が持つすべてのチップについて、選択されているチップがあれば削除する。
538 for( int i = this.譜面.SSTFormatScore.チップリスト.Count - 1; 0 <= i; i-- )
540 var chip = this.譜面.SSTFormatScore.チップリスト[ i ];
544 var chip変更前 = new SSTFormat.チップ( chip );
546 var cell = new UndoRedo.セル<SSTFormat.チップ>(
548 Undoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
549 変更対象.CopyFrom( 変更前 );
550 this.譜面.SSTFormatScore.チップリスト.Add( 変更対象 );
551 this.譜面.SSTFormatScore.チップリスト.Sort();
553 Redoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
554 this.譜面.SSTFormatScore.チップリスト.Remove( 変更対象 );
563 this.UndoRedo管理.セルを追加する( cell );
570 this.UndoRedo管理.トランザクション記録を終了する();
573 this.UndoRedo用GUIのEnabledを設定する();
574 this.選択チップの有無に応じて編集用GUIのEnabledを設定する();
578 protected void Actすべて選択する()
580 // 編集モードなら強制的に選択モードにする。
582 this.選択モードに切替えて関連GUIを設定する();
584 this.選択モード.全チップを選択する();
586 protected void Act選択モードにする()
588 this.選択モードに切替えて関連GUIを設定する();
590 protected void Act編集モードにする()
592 this.編集モードに切替えて関連GUIを設定する();
594 protected void Actモードを切替える()
598 this.編集モードに切替えて関連GUIを設定する();
602 this.選択モードに切替えて関連GUIを設定する();
605 protected void Act検索する()
607 this.選択モード.検索する(); // 現在のモードに関わらず、検索はすべて選択モードオブジェクトが行う。
609 protected void Actガイド間隔を変更する( int n分 )
613 if( !( new[] { 4, 6, 8, 12, 16, 24, 32, 48, 64, 128, 0 }.Contains( n分 ) ) )
614 throw new ArgumentException( $"不正なガイド間隔({n分})が指定されました。" );
617 #region " 新しいガイド間隔を設定する。"
620 this.譜面.現在のガイド間隔を変更する( n分 ); // 譜面オブジェクトとも共有。
623 #region " ガイド間隔関連GUI(メニュー、コンボボックス)を更新する。"
625 // 一度すべてのガイド間隔メニューのチェックをはずし、制定された分数のメニューだけをチェックする。
627 this.toolStripMenuItemガイド間隔4分.CheckState = CheckState.Unchecked;
628 this.toolStripMenuItemガイド間隔6分.CheckState = CheckState.Unchecked;
629 this.toolStripMenuItemガイド間隔8分.CheckState = CheckState.Unchecked;
630 this.toolStripMenuItemガイド間隔12分.CheckState = CheckState.Unchecked;
631 this.toolStripMenuItemガイド間隔16分.CheckState = CheckState.Unchecked;
632 this.toolStripMenuItemガイド間隔24分.CheckState = CheckState.Unchecked;
633 this.toolStripMenuItemガイド間隔32分.CheckState = CheckState.Unchecked;
634 this.toolStripMenuItemガイド間隔48分.CheckState = CheckState.Unchecked;
635 this.toolStripMenuItemガイド間隔64分.CheckState = CheckState.Unchecked;
636 this.toolStripMenuItemガイド間隔128分.CheckState = CheckState.Unchecked;
637 this.toolStripMenuItemガイド間隔フリー.CheckState = CheckState.Unchecked;
641 // Menu と ComboBox の2つを変更することでイベントが2つ発生し、最終的に
642 // Actガイド間隔を変更する() を立て続けに2回呼び出してしまうことになるが……、まぁよしとする。
645 this.toolStripMenuItemガイド間隔4分.CheckState = CheckState.Checked;
646 this.toolStripComboBoxガイド間隔.SelectedIndex = 0;
650 this.toolStripMenuItemガイド間隔6分.CheckState = CheckState.Checked;
651 this.toolStripComboBoxガイド間隔.SelectedIndex = 1;
655 this.toolStripMenuItemガイド間隔8分.CheckState = CheckState.Checked;
656 this.toolStripComboBoxガイド間隔.SelectedIndex = 2;
660 this.toolStripMenuItemガイド間隔12分.CheckState = CheckState.Checked;
661 this.toolStripComboBoxガイド間隔.SelectedIndex = 3;
665 this.toolStripMenuItemガイド間隔16分.CheckState = CheckState.Checked;
666 this.toolStripComboBoxガイド間隔.SelectedIndex = 4;
670 this.toolStripMenuItemガイド間隔24分.CheckState = CheckState.Checked;
671 this.toolStripComboBoxガイド間隔.SelectedIndex = 5;
675 this.toolStripMenuItemガイド間隔32分.CheckState = CheckState.Checked;
676 this.toolStripComboBoxガイド間隔.SelectedIndex = 6;
680 this.toolStripMenuItemガイド間隔48分.CheckState = CheckState.Checked;
681 this.toolStripComboBoxガイド間隔.SelectedIndex = 7;
685 this.toolStripMenuItemガイド間隔64分.CheckState = CheckState.Checked;
686 this.toolStripComboBoxガイド間隔.SelectedIndex = 8;
690 this.toolStripMenuItemガイド間隔128分.CheckState = CheckState.Checked;
691 this.toolStripComboBoxガイド間隔.SelectedIndex = 9;
695 this.toolStripMenuItemガイド間隔フリー.CheckState = CheckState.Checked;
696 this.toolStripComboBoxガイド間隔.SelectedIndex = 10;
703 this.pictureBox譜面パネル.Invalidate();
707 protected void Actガイド間隔を拡大する()
709 switch( this.現在のガイド間隔 )
712 case 6: this.Actガイド間隔を変更する( 4 ); break;
713 case 8: this.Actガイド間隔を変更する( 6 ); break;
714 case 12: this.Actガイド間隔を変更する( 8 ); break;
715 case 16: this.Actガイド間隔を変更する( 12 ); break;
716 case 24: this.Actガイド間隔を変更する( 16 ); break;
717 case 32: this.Actガイド間隔を変更する( 24 ); break;
718 case 48: this.Actガイド間隔を変更する( 32 ); break;
719 case 64: this.Actガイド間隔を変更する( 48 ); break;
720 case 128: this.Actガイド間隔を変更する( 64 ); break;
721 case 0: this.Actガイド間隔を変更する( 128 ); break;
724 protected void Actガイド間隔を縮小する()
726 switch( this.現在のガイド間隔 )
728 case 4: this.Actガイド間隔を変更する( 6 ); break;
729 case 6: this.Actガイド間隔を変更する( 8 ); break;
730 case 8: this.Actガイド間隔を変更する( 12 ); break;
731 case 12: this.Actガイド間隔を変更する( 16 ); break;
732 case 16: this.Actガイド間隔を変更する( 24 ); break;
733 case 24: this.Actガイド間隔を変更する( 32 ); break;
734 case 32: this.Actガイド間隔を変更する( 48 ); break;
735 case 48: this.Actガイド間隔を変更する( 64 ); break;
736 case 64: this.Actガイド間隔を変更する( 128 ); break;
737 case 128: this.Actガイド間隔を変更する( 0 ); break;
741 protected void Act譜面拡大率を変更する( int n倍 )
743 if( ( 1 > n倍 ) || ( 10 < n倍 ) )
744 throw new ArgumentException( $"不正な譜面拡大率({n倍})が指定されました。" );
746 this.toolStripComboBox譜面拡大率.SelectedIndex = ( n倍 - 1 );
749 protected void Act最初から再生する()
751 this.Act指定された小節の先頭から再生する( 小節番号: 0 );
753 protected void Act現在位置から再生する()
756 int 小節番号 = this.譜面.譜面内絶対位置gridにおける小節の番号と小節先頭の位置gridを返す( this.譜面.現在のカレントラインの譜面内絶対位置grid, out 位置grid );
757 this.Act指定された小節の先頭から再生する( 小節番号 );
759 protected void Act現在位置からBGMのみ再生する()
762 int 小節番号 = this.譜面.譜面内絶対位置gridにおける小節の番号と小節先頭の位置gridを返す( this.譜面.現在のカレントラインの譜面内絶対位置grid, out 位置grid );
763 this.Act指定された小節の先頭から再生する( 小節番号, 仮想ドラムを使う: false );
765 protected void Act指定された小節の先頭から再生する( int 小節番号, bool 仮想ドラムを使う = true )
767 if( this.Config.ViewerPath.Nullまたは空である() ||
768 ( false == File.Exists( this.Config.ViewerPath ) ) )
771 // 前回のテンポラリファイルが存在していれば削除する。
772 if( File.Exists( this.最後にプレイヤーに渡した一時ファイル名 ) )
773 File.Delete( this.最後にプレイヤーに渡した一時ファイル名 );
775 // 譜面を新しくテンポラリファイルとして出力する。
778 this.最後にプレイヤーに渡した一時ファイル名 = Path.Combine( this.作業フォルダパス, Path.GetRandomFileName() );
779 } while( File.Exists( this.最後にプレイヤーに渡した一時ファイル名 ) ); // 同一名のファイルが存在してたらもう一度。(まずないだろうが)
782 this.最後にプレイヤーに渡した一時ファイル名,
783 一時ファイルである: true ); // 一時ファイルなので、「最近使ったファイル一覧」には残さない。
786 this.SSTサービスが起動していれば取得する();
788 // SSTサービスが起動していない場合は、Viewer プロセスを起動する。
789 if( null == this.SSTサービス )
793 Process.Start( this.Config.ViewerPath );
800 // Viewer の提供するSSTサービスへ接続する。
801 for( int retry = 0; retry < 10; retry++ ) // 最大10回リトライ。
803 this.SSTサービスが起動していれば取得する();
805 if( null != this.SSTサービス )
806 break; // サービスに接続できた。
809 System.Threading.Thread.Sleep( 500 );
811 if( null == this.SSTサービス )
813 this.Viewer再生関連GUIのEnabledを設定する();
814 return; // サービスへの接続に失敗した。
819 float 遅延ms = this.SSTサービス.GetSoundDelay();
820 if( this.譜面.SSTFormatScore.Header.サウンドデバイス遅延ms != 遅延ms )
822 this.textBoxサウンド遅延ms.Text = 遅延ms.ToString(); // GUI と
823 this.譜面.SSTFormatScore.Header.サウンドデバイス遅延ms = 遅延ms; // 譜面にセットする。
828 this.SSTサービス.ViewerPlay(
829 path: this.最後にプレイヤーに渡した一時ファイル名,
831 drumsSound: 仮想ドラムを使う );
833 protected void Act再生を停止する()
835 if( this.Config.ViewerPath.Nullまたは空である() ||
836 ( false == File.Exists( this.Config.ViewerPath ) ) )
839 // プレイヤーを、演奏停止オプションをつけて起動する。
840 Process.Start( this.Config.ViewerPath, @"-s" );
842 protected void Actオプションを設定する()
844 using( var dialog = new オプションダイアログ() )
846 // Config の現在の値をダイアログへ反映する。
847 dialog.checkBoxオートフォーカス.CheckState = ( this.Config.AutoFocus ) ? CheckState.Checked : CheckState.Unchecked;
848 dialog.checkBox最近使用したファイル.CheckState = ( this.Config.ShowRecentUsedFiles ) ? CheckState.Checked : CheckState.Unchecked;
849 dialog.numericUpDown最近使用したファイルの最大表示個数.Value = this.Config.MaxOfUsedRecentFiles;
850 dialog.textBoxViewerPath.Text = this.Config.ViewerPath;
852 if( DialogResult.OK == dialog.ShowDialog( this ) )
854 // 決定された値をダイアログから Config に反映する。
855 this.Config.AutoFocus = dialog.checkBoxオートフォーカス.Checked;
856 this.Config.ShowRecentUsedFiles = dialog.checkBox最近使用したファイル.Checked;
857 this.Config.MaxOfUsedRecentFiles = (int) dialog.numericUpDown最近使用したファイルの最大表示個数.Value;
858 this.Config.ViewerPath = dialog.textBoxViewerPath.Text;
860 this.Viewer再生関連GUIのEnabledを設定する();
863 this.ConfigのRecentUsedFilesをファイルメニューへ追加する();
866 this.Config.保存する( Path.Combine( this.ユーザフォルダパス, Properties.Resources.CONFIG_FILE_NAME ) );
870 // 画面を再描画してダイアログのゴミを消す。
873 protected void Actバージョンを表示する()
875 using( var dialog = new バージョン表示ダイアログ() )
876 dialog.ShowDialog( this );
878 protected void Act小節長倍率を変更する( int 小節番号 )
884 #region " 変更後の小節長倍率をユーザに入力させる。"
886 var db現在の小節長倍率 = this.譜面.SSTFormatScore.小節長倍率を取得する( 小節番号 );
887 using( var dialog = new 小節長倍率入力ダイアログ( 小節番号 ) )
889 dialog.倍率 = (float) db現在の小節長倍率;
890 dialog.後続も全部変更する = false;
892 if( DialogResult.OK != dialog.ShowDialog( this ) ) // キャンセルされたらここで中断。
895 変更後倍率 = (double) dialog.倍率;
896 変更終了小節番号 = ( dialog.後続も全部変更する ) ? this.譜面.SSTFormatScore.最大小節番号 : 小節番号;
904 this.UndoRedo管理.トランザクション記録を開始する();
906 for( int i = 変更開始小節番号; i <= 変更終了小節番号; i++ )
908 var 変更前倍率 = this.譜面.SSTFormatScore.小節長倍率を取得する( i );
910 #region " 新しい小節長倍率を設定する。"
912 var cell = new UndoRedo.セル<double>(
914 Undoアクション: ( 変更対象, 変更前, 変更後, 対象小節番号, 任意2 ) => {
915 this.譜面.SSTFormatScore.小節長倍率を設定する( (int) 対象小節番号, 変更前 );
918 Redoアクション: ( 変更対象, 変更前, 変更後, 対象小節番号, 任意2 ) => {
919 this.譜面.SSTFormatScore.小節長倍率を設定する( (int) 対象小節番号, 変更後 );
928 this.UndoRedo管理.セルを追加する( cell );
932 #region " チップを移動または削除する。"
934 int 変化量grid = (int) ( ( 変更後倍率 - 変更前倍率 ) * this.GRID_PER_PART );
936 for( int j = this.譜面.SSTFormatScore.チップリスト.Count - 1; j >= 0; j-- ) // 削除する場合があるので後ろからカウントする。
938 var chip = this.譜面.SSTFormatScore.チップリスト[ j ];
940 // (A) 変更対象の小節内のチップ → 移動なし。カウント変更あり。小節はみ出しチェックあり。
943 #region " 小節からはみ出したチップは、削除する。"
945 int 次小節の先頭位置grid = this.譜面.小節先頭の譜面内絶対位置gridを返す( i ) + (int) ( 変更後倍率 * this.GRID_PER_PART );
946 if( 次小節の先頭位置grid <= chip.譜面内絶対位置grid )
948 var chip変更前 = new SSTFormat.チップ( chip );
950 var cc = new UndoRedo.セル<SSTFormat.チップ>(
952 Undoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
953 変更対象.CopyFrom( 変更前 );
954 this.譜面.SSTFormatScore.チップリスト.Add( 変更対象 );
955 this.譜面.SSTFormatScore.チップリスト.Sort();
958 Redoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
959 this.譜面.SSTFormatScore.チップリスト.Remove( 変更対象 );
968 this.UndoRedo管理.セルを追加する( cc );
973 #region " 小節からはみ出さなかったチップは、カウント(小節解像度と小節内位置)を変更する。"
977 // 解像度が小さいと計算結果がおかしくなるので、無条件に解像度を上げる。
979 int 十分に大きな値 = this.GRID_PER_PART; // 充分に大きい数なら何でもいい。
980 if( 十分に大きな値 > chip.小節解像度 ) // 何度も乗算されたら値が肥大化しまくるので、制限をかける。
982 chip.小節解像度 *= 十分に大きな値;
983 chip.小節内位置 *= 十分に大きな値;
986 // 小節解像度を変更する。(小節内位置は変更しない。)
987 chip.小節解像度 = (int) ( 変更後倍率 * chip.小節解像度 );
993 // (B) 変更対象より先の小節内のチップ → 移動あり。カウントなし。小節はみ出しチェックなし。
994 else if( i < chip.小節番号 )
996 #region " チップを n変化量grid 移動する。"
998 var cc = new UndoRedo.セル<SSTFormat.チップ>(
1000 Undoアクション: ( 変更対象, 変更前, 変更後, _変化量grid, 任意2 ) => {
1001 変更対象.譜面内絶対位置grid -= (int) _変化量grid;
1004 Redoアクション: ( 変更対象, 変更前, 変更後, _変化量grid, 任意2 ) => {
1005 変更対象.譜面内絶対位置grid += (int) _変化量grid;
1014 this.UndoRedo管理.セルを追加する( cc );
1026 this.UndoRedo管理.トランザクション記録を終了する();
1029 this.UndoRedo用GUIのEnabledを設定する();
1033 protected void Act小節を挿入する( int 挿入前小節番号 )
1035 // 挿入する新しい小節の小節長は、直前の(挿入前小節番号-1 の小節)と同じサイズとする。
1036 double 小節長倍率 = ( 0 < 挿入前小節番号 ) ? this.譜面.SSTFormatScore.小節長倍率を取得する( 挿入前小節番号 - 1 ) : 1.0;
1041 this.UndoRedo管理.トランザクション記録を開始する();
1043 #region " 後方のチップを移動する。"
1045 int 挿入に伴う増加量grid = (int) ( this.GRID_PER_PART * 小節長倍率 );
1047 foreach( var chip in this.譜面.SSTFormatScore.チップリスト )
1049 if( 挿入前小節番号 <= chip.小節番号 )
1051 var cell = new UndoRedo.セル<SSTFormat.チップ>(
1053 Undoアクション: ( 変更対象, 変更前, 変更後, _挿入に伴う増加量grid, 任意2 ) => {
1055 変更対象.譜面内絶対位置grid -= (int) _挿入に伴う増加量grid;
1057 Redoアクション: ( 変更対象, 変更前, 変更後, _挿入に伴う増加量grid, 任意2 ) => {
1059 変更対象.譜面内絶対位置grid += (int) _挿入に伴う増加量grid;
1067 this.UndoRedo管理.セルを追加する( cell );
1073 #region " 後方の小節長倍率を移動する。"
1075 var cc = new UndoRedo.セル<double>(
1077 Undoアクション: ( 変更対象, 変更前, 変更後, _挿入前小節番号, 任意2 ) => {
1078 this.譜面.SSTFormatScore.小節長倍率リスト.RemoveAt( (int) _挿入前小節番号 );
1081 Redoアクション: ( 変更対象, 変更前, 変更後, _挿入前小節番号, 任意2 ) => {
1082 this.譜面.SSTFormatScore.小節長倍率リスト.Insert( (int) _挿入前小節番号, 小節長倍率 );
1091 this.UndoRedo管理.セルを追加する( cc );
1098 this.UndoRedo管理.トランザクション記録を終了する();
1101 this.UndoRedo用GUIのEnabledを設定する();
1106 protected void Act小節を削除する( int 削除する小節番号 )
1108 double 削除する小節の小節長倍率 = this.譜面.SSTFormatScore.小節長倍率を取得する( 削除する小節番号 );
1113 this.UndoRedo管理.トランザクション記録を開始する();
1115 #region " 削除される小節内のチップをすべて削除する。"
1117 for( int i = this.譜面.SSTFormatScore.チップリスト.Count - 1; i >= 0; i-- )
1119 var chip = this.譜面.SSTFormatScore.チップリスト[ i ];
1121 if( 削除する小節番号 == chip.小節番号 )
1123 var chip変更前 = new SSTFormat.チップ( chip );
1125 var cell = new UndoRedo.セル<SSTFormat.チップ>(
1127 Undoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
1128 変更対象.CopyFrom( 変更前 );
1129 this.譜面.SSTFormatScore.チップリスト.Add( 変更対象 );
1130 this.譜面.SSTFormatScore.チップリスト.Sort();
1132 Redoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
1133 this.譜面.SSTFormatScore.チップリスト.Remove( 変更対象 );
1142 this.UndoRedo管理.セルを追加する( cell );
1148 #region " 後方のチップを移動する。"
1150 int 削除に伴う減少量grid = (int) ( this.GRID_PER_PART * 削除する小節の小節長倍率 );
1152 foreach( var chip in this.譜面.SSTFormatScore.チップリスト )
1154 if( 削除する小節番号 < chip.小節番号 )
1156 var cell = new UndoRedo.セル<SSTFormat.チップ>(
1158 Undoアクション: ( 変更対象, 変更前, 変更後, _削除に伴う減少量grid, 任意2 ) => {
1160 変更対象.譜面内絶対位置grid += (int) _削除に伴う減少量grid;
1162 Redoアクション: ( 変更対象, 変更前, 変更後, _削除に伴う減少量grid, 任意2 ) => {
1164 変更対象.譜面内絶対位置grid -= (int) _削除に伴う減少量grid;
1172 this.UndoRedo管理.セルを追加する( cell );
1178 #region " 後方の小節長倍率を移動する。"
1180 var cc = new UndoRedo.セル<double>(
1182 Undoアクション: ( 変更対象, 変更前, 変更後, _削除する小節番号, 任意2 ) => {
1183 this.譜面.SSTFormatScore.小節長倍率リスト.Insert( (int) _削除する小節番号, 変更前 );
1186 Redoアクション: ( 変更対象, 変更前, 変更後, _削除する小節番号, 任意2 ) => {
1187 this.譜面.SSTFormatScore.小節長倍率リスト.RemoveAt( (int) _削除する小節番号 );
1191 変更前の値: 削除する小節の小節長倍率,
1196 this.UndoRedo管理.セルを追加する( cc );
1203 this.UndoRedo管理.トランザクション記録を終了する();
1206 this.UndoRedo用GUIのEnabledを設定する();
1210 protected void Act小節の先頭へ移動する( int 小節番号 )
1215 else if( 小節番号 > this.譜面.SSTFormatScore.最大小節番号 )
1216 小節番号 = this.譜面.SSTFormatScore.最大小節番号;
1218 // 垂直スクロールバーを移動させると、画面も自動的に移動する。
1219 var bar = this.vScrollBar譜面用垂直スクロールバー;
1220 bar.Value = ( ( bar.Maximum + 1 ) - bar.LargeChange ) - this.譜面.小節先頭の譜面内絶対位置gridを返す( 小節番号 );
1225 protected void エディタを初期化する()
1227 this.編集中のファイル名 = null;
1229 #region " 各種オブジェクトを生成する。"
1232 this.譜面 = new C譜面( this ); // 譜面は、選択・編集モードよりも先に生成すること。
1234 this.UndoRedo管理 = new UndoRedo.管理();
1235 this.選択モード = new 選択モード( this );
1236 this.編集モード = new 編集モード( this );
1237 this.クリップボード = new クリップボード( this );
1245 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
1246 this.textBox曲名.Clear();
1248 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
1249 this.textBox説明.Clear();
1252 #region " Viewer 再生 "
1254 this.Viewer再生関連GUIのEnabledを設定する();
1259 this.Actガイド間隔を変更する( 16 ); // 初期値は 1/16。
1264 this.Act譜面拡大率を変更する( 1 ); // 初期値は x1.0。
1267 #region " Undo/Redo "
1269 this.次のプロパティ変更がUndoRedoリストに載るようにする();
1270 this.UndoRedo用GUIのEnabledを設定する();
1273 #region " 垂直スクロールバー "
1275 this.vScrollBar譜面用垂直スクロールバー.Minimum = 0;
1276 this.vScrollBar譜面用垂直スクロールバー.Maximum = ( this.譜面.全小節の高さgrid - 1 );
1277 this.vScrollBar譜面用垂直スクロールバー.SmallChange = ( this.GRID_PER_PART / 16 );
1278 this.vScrollBar譜面用垂直スクロールバー.LargeChange = this.GRID_PER_PART;
1279 this.vScrollBar譜面用垂直スクロールバー.Value = this.vScrollBar譜面用垂直スクロールバー.Maximum - this.vScrollBar譜面用垂直スクロールバー.LargeChange;
1285 this.編集モードに切替えて関連GUIを設定する();
1286 this.未保存である = false;
1288 protected DialogResult 未保存なら保存する()
1290 #region " 既に保存済みなら何もしない。"
1292 if( false == this.未保存である )
1293 return DialogResult.OK;
1296 #region "[編集中のデータを保存しますか?] ダイアログを表示し、回答を待つ。"
1298 var result = MessageBox.Show(
1299 Properties.Resources.MSG_編集中のデータを保存しますか,
1300 Properties.Resources.MSG_確認ダイアログのタイトル,
1301 MessageBoxButtons.YesNoCancel,
1302 MessageBoxIcon.Question,
1303 MessageBoxDefaultButton.Button1 );
1306 #region " YES なら上書き保存する。"
1308 if( DialogResult.Yes == result )
1312 #region " 画面を再描画してダイアログを消去する。"
1318 return result; // ダイアログの結果を返す。
1320 protected string ファイル保存ダイアログを開いてファイル名を取得する()
1322 DialogResult result;
1325 // ダイアログでファイル名を取得する。
1326 using( var dialog = new SaveFileDialog() {
1328 Filter = "SSTFファイル(*.sstf)|*.sstf",
1330 InitialDirectory = this.作業フォルダパス,
1333 result = dialog.ShowDialog( this );
1334 ファイル名 = dialog.FileName;
1337 // 画面を再描画してダイアログのゴミを消去する。
1340 // キャンセルされたら ""(空文字列)を返す。
1341 if( DialogResult.OK != result )
1344 // ファイルの拡張子を .sstf に変更。
1345 if( 0 == Path.GetExtension( ファイル名 ).Length )
1346 ファイル名 = Path.ChangeExtension( ファイル名, ".sstf" );
1350 protected void ファイルを読み込む( string ファイル名 )
1354 #region " [読み込み中です] ポップアップを表示する。"
1356 var msg = new Popupメッセージ(
1357 Properties.Resources.MSG_読み込み中です + Environment.NewLine +
1358 Properties.Resources.MSG_しばらくお待ち下さい );
1367 this.譜面.曲データファイルを読み込む( ファイル名 );
1369 // 最低でも 10 小節は存在させる。
1370 for( int n = this.譜面.SSTFormatScore.最大小節番号 + 1; n < 9; n++ )
1373 string 読み込み時の拡張子 = Path.GetExtension( ファイル名 ).ToLower();
1374 this.編集中のファイル名 = Path.ChangeExtension( Path.GetFileName( ファイル名 ), ".sstf" ); // 読み込んだファイルの拡張子を .sstf に変換。
1375 this.作業フォルダパス = Path.GetDirectoryName( ファイル名 );
1377 // 読み込んだファイルを [ファイル]メニューの最近使ったファイル一覧に追加する。
1378 this.Config.ファイルを最近使ったファイルの一覧に追加する( Path.Combine( this.作業フォルダパス, this.編集中のファイル名 ) );
1379 this.ConfigのRecentUsedFilesをファイルメニューへ追加する();
1382 譜面.SSTFormatScore.背景動画ファイル名 =
1383 ( from file in Directory.GetFiles( Path.GetDirectoryName( this.作業フォルダパス ) )
1384 where SSTFormat.スコア.背景動画のデフォルト拡張子s.Any( 拡張子名 => ( Path.GetExtension( file ).ToLower() == 拡張子名 ) )
1385 select file ).FirstOrDefault(); // 複数あったら、最初に見つけたほうを採用。1つも見つからなければ null。
1386 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
1387 this.textBox曲名.Text = 譜面.SSTFormatScore.Header.曲名;
1388 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
1389 this.textBox説明.Text = 譜面.SSTFormatScore.Header.説明文;
1390 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
1391 this.textBox背景動画.Text = Path.GetFileName( 譜面.SSTFormatScore.背景動画ファイル名 );
1392 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
1393 this.textBoxメモ.Text = ( this.譜面.SSTFormatScore.dicメモ.ContainsKey( 0 ) ) ? this.譜面.SSTFormatScore.dicメモ[ 0 ] : "";
1394 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
1395 this.textBoxサウンド遅延ms.Text = this.譜面.SSTFormatScore.Header.サウンドデバイス遅延ms.ToString();
1397 // ウィンドウのタイトルバーの表示変更(str編集中のファイル名 が確定した後に)
1398 this.未保存である = true; // 以前の状態によらず、確実に更新するようにする。
1400 // sstf 以外を読み込んだ場合は、未保存状態のままとする。
1401 if( 読み込み時の拡張子.ToLower() == ".sstf" )
1402 this.未保存である = false;
1404 catch( InvalidDataException )
1407 Properties.Resources.MSG_対応していないファイルです,
1408 Properties.Resources.MSG_確認ダイアログのタイトル,
1409 MessageBoxButtons.OK );
1412 #region "「読み込み中です」ポップアップを閉じる。 "
1418 // 最後に、ダイアログのゴミなどを消すために画面を再描画する。
1421 protected enum タブ種別 : int { 基本情報 = 0 }
1422 protected void タブを選択する( タブ種別 eタブ種別 )
1424 this.tabControl情報タブコンテナ.SelectedIndex = (int) eタブ種別;
1426 protected void 次のプロパティ変更がUndoRedoリストに載らないようにする()
1428 UndoRedo.管理.UndoRedoした直後である = true;
1430 protected void 次のプロパティ変更がUndoRedoリストに載るようにする()
1432 UndoRedo.管理.UndoRedoした直後である = false;
1434 protected void 垂直スクロールバーと譜面の上下位置を調整する()
1436 var bar = this.vScrollBar譜面用垂直スクロールバー;
1437 var box = this.pictureBox譜面パネル;
1438 var panel2 = this.splitContainer分割パネルコンテナ.Panel2;
1440 // 譜面パネルの長さをパネルに合わせて調整する。
1441 box.ClientSize = new Size(
1442 box.ClientSize.Width,
1443 panel2.ClientSize.Height - box.Location.Y );
1445 // 現在のバーの位置を割合で記憶する。
1446 var bar率 = (double) bar.Value / (double) ( bar.Maximum - bar.Minimum );
1448 // 新しい値域を設定した後、バーの位置を記憶しておいた割合で設定。
1450 bar.Maximum = this.譜面.全小節の高さgrid - 1;
1451 bar.Value = (int) ( ( bar.Maximum - bar.Minimum ) * bar率 );
1453 // 譜面長さが画面長さより短いなら、スクロールバーを表示しない。
1454 bar.Enabled = ( bar.Maximum > bar.LargeChange ) ? true : false;
1456 protected void Viewer再生関連GUIのEnabledを設定する()
1458 bool 各GUIは有効 = false;
1460 if( null != this.SSTサービス )
1462 // (A) SSTサービスが起動しているなら、各GUIは有効。
1465 else if( File.Exists( this.Config.ViewerPath ) )
1467 // (B) SSTサービスが起動していなくても、Viewer が存在するなら、各GUIは有効。
1472 // (C) SSTサービスが起動しておらず、Viewer も存在しないなら、各GUIは無効。
1476 this.toolStripButton先頭から再生.Enabled = 各GUIは有効;
1477 this.toolStripButton現在位置から再生.Enabled = 各GUIは有効;
1478 this.toolStripButton現在位置からBGMのみ再生.Enabled = 各GUIは有効;
1479 this.toolStripButton再生停止.Enabled = 各GUIは有効;
1481 this.toolStripMenuItem先頭から再生.Enabled = 各GUIは有効;
1482 this.toolStripMenuItem現在位置から再生.Enabled = 各GUIは有効;
1483 this.toolStripMenuItem現在位置からBGMのみ再生.Enabled = 各GUIは有効;
1484 this.toolStripMenuItem再生停止.Enabled = 各GUIは有効;
1486 protected void ConfigのRecentUsedFilesをファイルメニューへ追加する()
1488 #region " [ファイル] メニューから、[最近使ったファイルの一覧] をクリアする。"
1490 for( int i = 0; i < this.toolStripMenuItemファイル.DropDownItems.Count; i++ )
1492 var item = this.toolStripMenuItemファイル.DropDownItems[ i ];
1494 // ↓削除したくないサブメニューの一覧。これ以外のサブメニュー項目はすべて削除する。
1495 if( item != this.toolStripMenuItem新規作成 &&
1496 item != this.toolStripMenuItem開く &&
1497 item != this.toolStripMenuItem上書き保存 &&
1498 item != this.toolStripMenuItem名前を付けて保存 &&
1499 item != this.toolStripSeparator1 &&
1500 item != this.toolStripMenuItem終了 )
1502 this.toolStripMenuItemファイル.DropDownItems.Remove( item );
1503 i = -1; // 要素数が変わったので列挙しなおし。RemoveAll() はないのか。
1509 if( ( false == this.Config.ShowRecentUsedFiles ) || // 表示しない or
1510 ( 0 == this.Config.RecentUsedFiles.Count ) ) // 履歴が 0 件
1513 #region " Config が持つ履歴にそって、[ファイル] メニューにサブメニュー項目リストを追加する(ただし最大表示数まで)。"
1515 // [File] のサブメニューリストに項目が1つでもある場合は、履歴サブメニュー項目を追加する前に、[終了] の下にセパレータを入れる。手動で。
1516 bool セパレータの追加がまだ = true;
1518 // すべての [最近使ったファイル] について...
1519 for( int i = 0; i < this.Config.RecentUsedFiles.Count; i++ )
1522 if( this.Config.MaxOfUsedRecentFiles <= i )
1525 // ファイルパスを、サブメニュー項目として [ファイル] メニューに追加する。
1526 string ファイルパス = this.Config.RecentUsedFiles[ i ];
1527 if( string.IsNullOrEmpty( ファイルパス ) )
1530 // セパレータの追加がまだなら追加する。
1533 this.toolStripMenuItemファイル.DropDownItems.Add( new ToolStripSeparator() { Size = this.toolStripSeparator1.Size } );
1534 セパレータの追加がまだ = false;
1537 // ToolStripMenuItem を手動で作って [ファイル] のサブメニューリストに追加する。
1538 var item = new ToolStripMenuItem() {
1539 Name = "最近使ったファイル" + i,
1540 Size = this.toolStripMenuItem終了.Size,
1541 Text = "&" + i + " " + ファイルパス,
1543 item.Click += new EventHandler( this.toolStripMenuItem最近使ったファイル_Click );
1544 this.toolStripMenuItemファイル.DropDownItems.Add( item );
1546 // 追加したファイルが既に存在していないなら項目を無効化(グレー表示)する。
1547 if( false == File.Exists( ファイルパス ) )
1548 item.Enabled = false;
1553 protected Point 現在のマウス位置を譜面パネル内座標pxに変換して返す()
1555 return this.pictureBox譜面パネル.PointToClient( new Point( Cursor.Position.X, Cursor.Position.Y ) );
1557 protected void 現在のチップ音量をツールバーに表示する()
1559 this.toolStripLabel音量.Text = ( this.dic音量ラベル.ContainsKey( this.現在のチップ音量 ) ) ? this.dic音量ラベル[ this.現在のチップ音量 ] : @"???";
1561 protected void SSTサービスが起動していれば取得する()
1564 if( null == this.SSTファクトリ )
1565 this.SSTファクトリ = new ChannelFactory<SST.IStrokeStyleTService>( new NetNamedPipeBinding( NetNamedPipeSecurityMode.None ) );
1568 if( null == this.SSTサービス )
1572 this.SSTサービス = this.SSTファクトリ.CreateChannel( new EndpointAddress( "net.pipe://localhost/StrokeStyleT/Viewer" ) );
1574 catch( EndpointNotFoundException )
1576 this.SSTサービス = null; // 取得失敗。
1585 protected void メインフォーム_DragDrop( object sender, DragEventArgs e )
1587 string[] data = (string[]) e.Data.GetData( DataFormats.FileDrop );
1589 if( 1 <= data.Length )
1590 this.Act指定されたファイルを開く( data[ 0 ] ); // Dropされたファイルが複数個あっても、先頭のファイルだけを有効とする。
1592 protected void メインフォーム_DragEnter( object sender, DragEventArgs e )
1594 if( e.Data.GetDataPresent( DataFormats.FileDrop ) )
1596 e.Effect = DragDropEffects.Copy; // ファイルならコピーと見なす(カーソルがコピー型になる)
1600 e.Effect = DragDropEffects.None; // ファイルじゃないなら無視(カーソル変化なし)
1603 protected void メインフォーム_FormClosing( object sender, FormClosingEventArgs e )
1605 if( DialogResult.Cancel == this.未保存なら保存する() )
1619 protected void toolStripMenuItem新規作成_Click( object sender, EventArgs e )
1623 protected void toolStripMenuItem開く_Click( object sender, EventArgs e )
1627 protected void toolStripMenuItem上書き保存_Click( object sender, EventArgs e )
1631 protected void toolStripMenuItem名前を付けて保存_Click( object sender, EventArgs e )
1633 this.Act名前を付けて保存する();
1635 protected void toolStripMenuItem終了_Click( object sender, EventArgs e )
1639 protected void toolStripMenuItem最近使ったファイル_Click( object sender, EventArgs e )
1641 // ※このイベントハンドラに対応する「toolStripMenuItem最近使ったファイル」というアイテムはデザイナにはないので注意。
1642 // 「this.t最近使ったファイルをFileメニューへ追加する()」の中で、手動で作って追加したアイテムに対するハンドラである。
1644 this.Act指定されたファイルを開く( ( (ToolStripMenuItem) sender ).Text.Substring( 3 ) );
1648 protected void toolStripMenuItem元に戻す_Click( object sender, EventArgs e )
1652 protected void toolStripMenuItemやり直す_Click( object sender, EventArgs e )
1656 protected void toolStripMenuItem切り取り_Click( object sender, EventArgs e )
1660 protected void toolStripMenuItemコピー_Click( object sender, EventArgs e )
1664 protected void toolStripMenuItem貼り付け_Click( object sender, EventArgs e )
1666 var マウスの位置 = this.現在のマウス位置を譜面パネル内座標pxに変換して返す();
1668 // (A) マウスが譜面上になかった → 表示領域下辺から貼り付ける。
1669 if( ( ( 0 > マウスの位置.X ) || ( 0 > マウスの位置.Y ) ) ||
1670 ( ( マウスの位置.X > this.譜面パネルサイズ.Width ) || ( マウスの位置.Y > this.譜面パネルサイズ.Height ) ) )
1672 this.Act貼り付ける( this.譜面.現在の譜面表示下辺の譜面内絶対位置grid );
1674 // (B) マウスが譜面上にある → そこから貼り付ける。
1677 this.Act貼り付ける( this.譜面.譜面パネル内Y座標pxにおける譜面内絶対位置gridをガイド幅単位で返す( マウスの位置.Y ) );
1680 protected void toolStripMenuItem削除_Click( object sender, EventArgs e )
1684 protected void toolStripMenuItemすべて選択_Click( object sender, EventArgs e )
1688 protected void toolStripMenuItem選択モード_Click( object sender, EventArgs e )
1690 this.選択モードに切替えて関連GUIを設定する();
1692 protected void toolStripMenuItem編集モード_Click( object sender, EventArgs e )
1694 this.編集モードに切替えて関連GUIを設定する();
1696 protected void toolStripMenuItemモード切替え_Click( object sender, EventArgs e )
1700 this.編集モードに切替えて関連GUIを設定する();
1704 this.選択モードに切替えて関連GUIを設定する();
1707 protected void toolStripMenuItem検索_Click( object sender, EventArgs e )
1713 protected void toolStripMenuItemガイド間隔4分_Click( object sender, EventArgs e )
1715 this.Actガイド間隔を変更する( 4 );
1717 protected void toolStripMenuItemガイド間隔6分_Click( object sender, EventArgs e )
1719 this.Actガイド間隔を変更する( 6 );
1721 protected void toolStripMenuItemガイド間隔8分_Click( object sender, EventArgs e )
1723 this.Actガイド間隔を変更する( 8 );
1725 protected void toolStripMenuItemガイド間隔12分_Click( object sender, EventArgs e )
1727 this.Actガイド間隔を変更する( 12 );
1729 protected void toolStripMenuItemガイド間隔16分_Click( object sender, EventArgs e )
1731 this.Actガイド間隔を変更する( 16 );
1733 protected void toolStripMenuItemガイド間隔24分_Click( object sender, EventArgs e )
1735 this.Actガイド間隔を変更する( 24 );
1737 protected void toolStripMenuItemガイド間隔32分_Click( object sender, EventArgs e )
1739 this.Actガイド間隔を変更する( 32 );
1741 protected void toolStripMenuItemガイド間隔48分_Click( object sender, EventArgs e )
1743 this.Actガイド間隔を変更する( 48 );
1745 protected void toolStripMenuItemガイド間隔64分_Click( object sender, EventArgs e )
1747 this.Actガイド間隔を変更する( 64 );
1749 protected void toolStripMenuItemガイド間隔128分_Click( object sender, EventArgs e )
1751 this.Actガイド間隔を変更する( 128 );
1753 protected void toolStripMenuItemガイド間隔フリー_Click( object sender, EventArgs e )
1755 this.Actガイド間隔を変更する( 0 );
1757 protected void toolStripMenuItemガイド間隔拡大_Click( object sender, EventArgs e )
1759 this.Actガイド間隔を拡大する();
1761 protected void toolStripMenuItemガイド間隔縮小_Click( object sender, EventArgs e )
1763 this.Actガイド間隔を縮小する();
1767 protected void toolStripMenuItem先頭から再生_Click( object sender, EventArgs e )
1771 protected void toolStripMenuItem現在位置から再生_Click( object sender, EventArgs e )
1773 this.Act現在位置から再生する();
1775 protected void toolStripMenuItem現在位置からBGMのみ再生_Click( object sender, EventArgs e )
1777 this.Act現在位置からBGMのみ再生する();
1779 protected void toolStripMenuItem再生停止_Click( object sender, EventArgs e )
1785 protected void toolStripMenuItemオプション_Click( object sender, EventArgs e )
1787 this.Actオプションを設定する();
1791 protected void toolStripMenuItemバージョン_Click( object sender, EventArgs e )
1793 this.Actバージョンを表示する();
1799 protected void toolStripButton新規作成_Click( object sender, EventArgs e )
1803 protected void toolStripButton開く_Click( object sender, EventArgs e )
1807 protected void toolStripButton上書き保存_Click( object sender, EventArgs e )
1811 protected void toolStripButton切り取り_Click( object sender, EventArgs e )
1815 protected void toolStripButtonコピー_Click( object sender, EventArgs e )
1819 protected void toolStripButton貼り付け_Click( object sender, EventArgs e )
1821 var マウスの位置 = this.現在のマウス位置を譜面パネル内座標pxに変換して返す();
1823 // (A) マウスが譜面上になかった → 表示領域下辺から貼り付ける。
1824 if( ( ( マウスの位置.X < 0 ) || ( マウスの位置.Y < 0 ) ) ||
1825 ( ( マウスの位置.X > this.譜面パネルサイズ.Width ) || ( マウスの位置.Y > this.譜面パネルサイズ.Height ) ) )
1827 this.Act貼り付ける( this.譜面.現在の譜面表示下辺の譜面内絶対位置grid );
1829 // (B) マウスが譜面上にある → そこから貼り付ける。
1832 this.Act貼り付ける( this.譜面.譜面パネル内Y座標pxにおける譜面内絶対位置gridをガイド幅単位で返す( マウスの位置.Y ) );
1835 protected void toolStripButton削除_Click( object sender, EventArgs e )
1840 protected void toolStripButton元に戻す_Click( object sender, EventArgs e )
1844 protected void toolStripButtonやり直す_Click( object sender, EventArgs e )
1849 protected void toolStripComboBox譜面拡大率_SelectedIndexChanged( object sender, EventArgs e )
1851 this.Act譜面拡大率を変更する( this.toolStripComboBox譜面拡大率.SelectedIndex + 1 );
1853 protected void toolStripComboBoxガイド間隔_SelectedIndexChanged( object sender, EventArgs e )
1855 switch( this.toolStripComboBoxガイド間隔.SelectedIndex )
1858 this.Actガイド間隔を変更する( 4 );
1862 this.Actガイド間隔を変更する( 6 );
1866 this.Actガイド間隔を変更する( 8 );
1870 this.Actガイド間隔を変更する( 12 );
1874 this.Actガイド間隔を変更する( 16 );
1878 this.Actガイド間隔を変更する( 24 );
1882 this.Actガイド間隔を変更する( 32 );
1886 this.Actガイド間隔を変更する( 48 );
1890 this.Actガイド間隔を変更する( 64 );
1894 this.Actガイド間隔を変更する( 128 );
1898 this.Actガイド間隔を変更する( 0 );
1903 protected void toolStripButton選択モード_Click( object sender, EventArgs e )
1907 protected void toolStripButton編集モード_Click( object sender, EventArgs e )
1912 protected void toolStripButton先頭から再生_Click( object sender, EventArgs e )
1916 protected void toolStripButton現在位置から再生_Click( object sender, EventArgs e )
1918 this.Act現在位置から再生する();
1920 protected void toolStripButton現在位置からBGMのみ再生_Click( object sender, EventArgs e )
1922 this.Act現在位置からBGMのみ再生する();
1924 protected void toolStripButton再生停止_Click( object sender, EventArgs e )
1929 protected void toolStripButton音量Down_Click( object sender, EventArgs e )
1931 int 新音量 = this.現在のチップ音量 - 1;
1932 this.現在のチップ音量 = ( 新音量 < メインフォーム.最小音量 ) ? メインフォーム.最小音量 : 新音量;
1934 this.現在のチップ音量をツールバーに表示する();
1936 protected void toolStripButton音量UP_Click( object sender, EventArgs e )
1938 int 新音量 = this.現在のチップ音量 + 1;
1939 this.現在のチップ音量 = ( 新音量 > メインフォーム.最大音量 ) ? メインフォーム.最大音量 : 新音量;
1941 this.現在のチップ音量をツールバーに表示する();
1945 #region " 分割パネルコンテナ、譜面パネル、スクロールバー "
1947 protected void pictureBox譜面パネル_MouseClick( object sender, MouseEventArgs e )
1950 this.pictureBox譜面パネル.Focus();
1952 // 選択・編集モードオブジェクトのいずれかへ処理を引き継ぐ。
1955 this.選択モード.MouseClick( e );
1959 this.編集モード.MouseClick( e );
1962 protected void pictureBox譜面パネル_MouseDown( object sender, MouseEventArgs e )
1964 // 選択モードオブジェクトへ処理を引き継ぐ。
1966 this.選択モード.MouseDown( e );
1968 protected void pictureBox譜面パネル_MouseEnter( object sender, EventArgs e )
1970 // オートフォーカスが有効の場合、譜面にマウスが入ったら譜面がフォーカスを得る。"
1971 if( this.Config.AutoFocus )
1972 this.pictureBox譜面パネル.Focus();
1974 protected void pictureBox譜面パネル_MouseLeave( object sender, EventArgs e )
1976 // 編集モードオブジェクトへ処理を引き継ぐ。
1978 this.編集モード.MouseLeave( e );
1980 protected void pictureBox譜面パネル_MouseMove( object sender, MouseEventArgs e )
1982 // 選択・編集モードオブジェクトのいずれかへ処理を引き継ぐ。
1985 this.選択モード.MouseMove( e );
1989 this.編集モード.MouseMove( e );
1992 protected void pictureBox譜面パネル_Paint( object sender, PaintEventArgs e )
1994 if( false == this.初期化完了 )
1995 return; // 初期化が終わってないのに呼び出されることがあるので、その場合は無視。
1997 #region " 小節数が変わってたら、スクロールバーの値域を調整する。"
1999 int 全譜面の高さgrid = this.譜面.全小節の高さgrid;
2001 if( this.vScrollBar譜面用垂直スクロールバー.Maximum != 全譜面の高さgrid - 1 ) // 小節数が変わっている
2003 // 譜面の高さ(grid)がどれだけ変わったか?
2004 int 増加分grid = ( 全譜面の高さgrid - 1 ) - this.vScrollBar譜面用垂直スクロールバー.Maximum;
2006 #region " スクロールバーの状態を新しい譜面の高さに合わせる。"
2009 int value = this.vScrollBar譜面用垂直スクロールバー.Value; // 次の式で Maximum が Value より小さくなると例外が発生するので、
2010 this.vScrollBar譜面用垂直スクロールバー.Value = 0; // Value のバックアップを取っておいて、ひとまず 0 にする。
2011 this.vScrollBar譜面用垂直スクロールバー.Maximum = 全譜面の高さgrid - 1;
2013 int newValue = value + 増加分grid;
2015 // オーバーフローしないようクリッピングする。
2018 this.vScrollBar譜面用垂直スクロールバー.Value = 0;
2020 else if( ( this.vScrollBar譜面用垂直スクロールバー.Maximum - this.vScrollBar譜面用垂直スクロールバー.LargeChange ) <= newValue )
2022 this.vScrollBar譜面用垂直スクロールバー.Value = this.vScrollBar譜面用垂直スクロールバー.Maximum - this.vScrollBar譜面用垂直スクロールバー.LargeChange;
2026 this.vScrollBar譜面用垂直スクロールバー.Value = newValue;
2031 #region " 譜面表示下辺の位置を更新する。"
2033 this.譜面.現在の譜面表示下辺の譜面内絶対位置grid =
2034 ( ( this.vScrollBar譜面用垂直スクロールバー.Maximum - this.vScrollBar譜面用垂直スクロールバー.LargeChange ) + 1 ) - this.vScrollBar譜面用垂直スクロールバー.Value;
2042 this.譜面.描画する( e.Graphics, this.pictureBox譜面パネル );
2046 // 選択・編集モードオブジェクトのいずれかへ処理を引き継ぐ。
2049 this.選択モード.Paint( e );
2053 this.編集モード.Paint( e );
2056 protected void pictureBox譜面パネル_PreviewKeyDown( object sender, PreviewKeyDownEventArgs e )
2058 if( Keys.Prior == e.KeyCode )
2060 #region " PageUp → 移動量に対応する grid だけ垂直つまみを移動させる。あとはこの移動で生じる ChangedValue イベントで処理。"
2062 int 移動すべき数grid = -this.GRID_PER_PART;
2063 int 新しい位置 = this.vScrollBar譜面用垂直スクロールバー.Value + 移動すべき数grid;
2064 int 最小値 = this.vScrollBar譜面用垂直スクロールバー.Minimum;
2065 int 最大値 = ( this.vScrollBar譜面用垂直スクロールバー.Maximum + 1 ) - this.vScrollBar譜面用垂直スクロールバー.LargeChange;
2071 else if( 新しい位置 > 最大値 )
2075 this.vScrollBar譜面用垂直スクロールバー.Value = 新しい位置;
2079 else if( Keys.Next == e.KeyCode )
2081 #region " PageDown → 移動量に対応する grid だけ垂直つまみを移動させる。あとはこの移動で生じる ChangedValue イベントで処理。"
2083 int 移動すべき数grid = this.GRID_PER_PART;
2084 int 新しい位置 = this.vScrollBar譜面用垂直スクロールバー.Value + 移動すべき数grid;
2085 int 最小値 = this.vScrollBar譜面用垂直スクロールバー.Minimum;
2086 int 最大値 = ( this.vScrollBar譜面用垂直スクロールバー.Maximum + 1 ) - this.vScrollBar譜面用垂直スクロールバー.LargeChange;
2092 else if( 新しい位置 > 最大値 )
2096 this.vScrollBar譜面用垂直スクロールバー.Value = 新しい位置;
2102 // 編集モードオブジェクトへ処理を引き継ぐ。
2104 this.編集モード.PreviewKeyDown( e );
2108 protected void splitContainer分割パネルコンテナ_MouseWheel( object sender, MouseEventArgs e )
2110 if( false == this.初期化完了 )
2111 return; // 初期化が終わってないのに呼び出されることがあるので、その場合は無視。
2113 #region " 移動量に対応する grid だけ垂直つまみを移動させる。あとはこの移動で生じる ChangedValue イベントで処理する。"
2118 // e.Delta は、スクロールバーを下へ動かしたいときに負、上へ動かしたいときに正となる。
2119 int 移動すべき行数 = ( -e.Delta * SystemInformation.MouseWheelScrollLines ) / 120;
2122 int 移動すべき数grid = 移動すべき行数 * ( this.GRID_PER_PART / 4 );
2124 // スクロールバーのつまみを移動する。
2125 int 新しい位置 = this.vScrollBar譜面用垂直スクロールバー.Value + 移動すべき数grid;
2126 int 最小値 = this.vScrollBar譜面用垂直スクロールバー.Minimum;
2127 int 最大値 = ( this.vScrollBar譜面用垂直スクロールバー.Maximum + 1 ) - this.vScrollBar譜面用垂直スクロールバー.LargeChange;
2133 else if( 新しい位置 > 最大値 )
2137 this.vScrollBar譜面用垂直スクロールバー.Value = 新しい位置;
2141 protected void splitContainer分割パネルコンテナ_Panel2_SizeChanged( object sender, EventArgs e )
2143 if( false == this.初期化完了 )
2144 return; // 初期化が終わってないのに呼び出されることがあるので、その場合は無視。
2146 this.垂直スクロールバーと譜面の上下位置を調整する();
2148 protected void splitContainer分割パネルコンテナ_Panel2_Paint( object sender, PaintEventArgs e )
2150 if( false == this.初期化完了 )
2151 return; // 初期化が終わってないのに呼び出されることがあるので、その場合は無視。
2154 var メモ領域左上隅の位置 = new PointF() {
2155 X = this.譜面.レーンの合計幅px,
2156 Y = this.pictureBox譜面パネル.Location.Y,
2159 #region " 見出し<小節メモ>を描画する。"
2161 g.DrawString( Properties.Resources.MSG_小節メモ, this.メモ用フォント, Brushes.White, PointF.Add( メモ領域左上隅の位置, new Size( 24, -24 )/*マージン*/ ) );
2164 #region " 小節メモを描画する。"
2167 // グリッド値は 上辺>下辺 なので注意。
2168 int パネル下辺grid = this.譜面.現在の譜面表示下辺の譜面内絶対位置grid;
2169 int パネル上辺grid = パネル下辺grid + ( this.pictureBox譜面パネル.ClientSize.Height * this.GRID_PER_PIXEL );
2170 int 開始小節番号 = this.譜面.現在譜面表示下辺に存在している小節番号;
2172 for( int 小節番号 = 開始小節番号; 小節番号 <= this.譜面.SSTFormatScore.最大小節番号; 小節番号++ )
2174 int 小節の下辺grid = this.譜面.小節先頭の譜面内絶対位置gridを返す( 小節番号 );
2175 int 小節の上辺grid = 小節の下辺grid + this.譜面.小節長をグリッドで返す( 小節番号 );
2177 if( 小節の下辺grid > パネル上辺grid )
2178 break; // 小節が画面上方にはみ出し切ってしまったらそこで終了。
2180 if( this.譜面.SSTFormatScore.dicメモ.ContainsKey( 小節番号 ) )
2182 string メモ = this.譜面.SSTFormatScore.dicメモ[ 小節番号 ];
2184 string[] lines = メモ.Split( new string[] { Environment.NewLine }, StringSplitOptions.None );
2185 int 行数 = lines.Length;
2187 var メモの位置 = new PointF() {
2188 X = メモ領域左上隅の位置.X + 4, // + 4 はマージン
2189 Y = メモ領域左上隅の位置.Y + ( パネル上辺grid - 小節の下辺grid ) / this.GRID_PER_PIXEL - ( 行数 * 16 ), // 9pt = だいたい16px
2191 g.DrawString( メモ, this.メモ用フォント, Brushes.White, メモの位置 );
2198 protected void vScrollBar譜面用垂直スクロールバー_ValueChanged( object sender, EventArgs e )
2200 if( false == this.初期化完了 )
2201 return; // 初期化が終わってないのに呼び出されることがあるので、その場合は無視。
2203 var bar = vScrollBar譜面用垂直スクロールバー;
2208 this.譜面.現在の譜面表示下辺の譜面内絶対位置grid = ( ( bar.Maximum + 1 ) - bar.LargeChange ) - bar.Value;
2210 // 編集モードの場合、カーソルのgrid位置を再計算。
2213 this.編集モード.MouseMove(
2214 new MouseEventArgs( MouseButtons.None, 0, this.編集モード.現在のチップカーソル領域.X, this.編集モード.現在のチップカーソル領域.Y, 0 ) );
2218 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2219 this.numericUpDownメモ用小節番号.Value = this.譜面.現在カレントラインに存在している小節番号;
2220 this.次のプロパティ変更がUndoRedoリストに載るようにする();
2223 this.splitContainer分割パネルコンテナ.Panel2.Refresh();
2230 protected void toolStripMenuItem選択チップの切り取り_Click( object sender, EventArgs e )
2234 protected void toolStripMenuItem選択チップのコピー_Click( object sender, EventArgs e )
2238 protected void toolStripMenuItem選択チップの貼り付け_Click( object sender, EventArgs e )
2240 // メニューが開かれたときのマウスの座標を取得。
2241 // ※メニューは必ずマウス位置を左上にして表示されるとは限らないため、メニューの表示位置からは取得しないこと。
2242 var マウスの位置 = this.選択モードのコンテクストメニューを開いたときのマウスの位置;
2244 if( this.譜面.譜面パネル内X座標pxにある編集レーンを返す( マウスの位置.X ) == 編集レーン種別.Unknown )
2245 return; // クリックされた場所にレーンがないなら無視。
2248 this.Act貼り付ける( this.譜面.譜面パネル内Y座標pxにおける譜面内絶対位置gridをガイド幅単位で返す( マウスの位置.Y ) );
2250 protected void toolStripMenuItem選択チップの削除_Click( object sender, EventArgs e )
2254 protected void toolStripMenuItemすべてのチップの選択_Click( object sender, EventArgs e )
2256 // 編集モードなら強制的に選択モードにする。
2258 this.選択モードに切替えて関連GUIを設定する();
2261 this.選択モード.全チップを選択する();
2263 protected void toolStripMenuItem小節長変更_Click( object sender, EventArgs e )
2265 // メニューが開かれたときのマウスの座標を取得。
2266 // ※メニューは必ずマウス位置を左上にして表示されるとは限らないため、メニューの表示位置からは取得しないこと。
2267 var マウスの位置 = this.選択モードのコンテクストメニューを開いたときのマウスの位置;
2269 if( this.譜面.譜面パネル内X座標pxにある編集レーンを返す( マウスの位置.X ) == 編集レーン種別.Unknown )
2270 return; // クリックされた場所にレーンがないなら無視。
2273 this.Act小節長倍率を変更する( this.譜面.譜面パネル内Y座標pxにおける小節番号を返す( マウスの位置.Y ) );
2275 protected void toolStripMenuItem小節の挿入_Click( object sender, EventArgs e )
2277 // メニューが開かれたときのマウスの座標を取得。
2278 // ※メニューは必ずマウス位置を左上にして表示されるとは限らないため、メニューの表示位置からは取得しないこと。
2279 var マウスの位置 = this.選択モードのコンテクストメニューを開いたときのマウスの位置;
2281 if( this.譜面.譜面パネル内X座標pxにある編集レーンを返す( マウスの位置.X ) == 編集レーン種別.Unknown )
2282 return; // クリックされた場所にレーンがないなら無視。
2285 this.Act小節を挿入する( this.譜面.譜面パネル内Y座標pxにおける小節番号を返す( マウスの位置.Y ) );
2287 protected void toolStripMenuItem小節の削除_Click( object sender, EventArgs e )
2289 // メニューが開かれたときのマウスの座標を取得。
2290 // ※メニューは必ずマウス位置を左上にして表示されるとは限らないため、メニューの表示位置からは取得しないこと。
2291 var マウスの位置 = this.選択モードのコンテクストメニューを開いたときのマウスの位置;
2293 if( this.譜面.譜面パネル内X座標pxにある編集レーンを返す( マウスの位置.X ) == 編集レーン種別.Unknown )
2294 return; // クリックされた場所にレーンがないなら無視。
2297 this.Act小節を削除する( this.譜面.譜面パネル内Y座標pxにおける小節番号を返す( マウスの位置.Y ) );
2303 protected void textBox曲名_TextChanged( object sender, EventArgs e )
2305 #region " この変更が Undo/Redo したことによるものではない場合、UndoRedoセルを追加 or 修正する。"
2307 if( false == UndoRedo.管理.UndoRedoした直後である )
2310 var cell = this.UndoRedo管理.Undoするセルを取得して返す_見るだけ();
2312 if( ( null != cell ) && cell.所有権がある( this.textBox曲名 ) )
2314 // (A) 所有者である → 最新のセルの "変更後の値" を現在のコントロールの値に更新する。
2315 ( (UndoRedo.セル<string>) cell ).変更後の値 = this.textBox曲名.Text;
2319 // (B) 所有者ではない → 以下のようにセルを新規追加する。
2322 // "所有者ID" ← 対象となるコンポーネントオブジェクト
2323 var cc = new UndoRedo.セル<string>(
2324 所有者ID: this.textBox曲名,
2325 Undoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
2326 this.タブを選択する( タブ種別.基本情報 );
2327 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2328 this.textBox曲名.Text = 変更前;
2329 this.textBox曲名.Focus();
2331 Redoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
2332 this.タブを選択する( タブ種別.基本情報 );
2333 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2334 this.textBox曲名.Text = 変更後;
2335 this.textBox曲名.Focus();
2338 変更前の値: this.textBox曲名_以前の値,
2339 変更後の値: this.textBox曲名.Text,
2343 this.UndoRedo管理.セルを追加する( cc );
2346 this.UndoRedo用GUIのEnabledを設定する();
2352 this.textBox曲名_以前の値 = this.textBox曲名.Text; // 以前の値 ← 現在の値
2353 UndoRedo.管理.UndoRedoした直後である = false;
2357 譜面.SSTFormatScore.Header.曲名 = this.textBox曲名.Text;
2359 protected void textBox曲名_Leave( object sender, EventArgs e )
2361 // 最新の UndoRedoセル の所有権を放棄する。
2362 this.UndoRedo管理.Undoするセルを取得して返す_見るだけ()?.所有権を放棄する( this.textBox曲名 );
2364 protected string textBox曲名_以前の値 = "";
2366 protected void textBox説明_TextChanged( object sender, EventArgs e )
2368 #region " この変更が Undo/Redo したことによるものではない場合、UndoRedoセルを追加 or 修正する。"
2370 if( false == UndoRedo.管理.UndoRedoした直後である )
2373 var cell = this.UndoRedo管理.Undoするセルを取得して返す_見るだけ();
2374 if( ( null != cell ) && cell.所有権がある( this.textBox説明 ) )
2376 // (A) 所有者である → 最新のセルの "変更後の値" を現在のコントロールの値に更新。
2378 ( (UndoRedo.セル<string>) cell ).変更後の値 = this.textBox説明.Text;
2382 // (B) 所有者ではない → 以下のようにセルを新規追加する。
2385 // "所有者ID" ← 対象となるコンポーネントオブジェクト
2386 var cc = new UndoRedo.セル<string>(
2387 所有者ID: this.textBox説明,
2388 Undoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
2389 this.タブを選択する( タブ種別.基本情報 );
2390 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2391 this.textBox説明.Text = 変更前;
2392 this.textBox説明.Focus();
2394 Redoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
2395 this.タブを選択する( タブ種別.基本情報 );
2396 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2397 this.textBox説明.Text = 変更後;
2398 this.textBox説明.Focus();
2401 変更前の値: this.textBox説明_以前の値,
2402 変更後の値: this.textBox説明.Text,
2406 this.UndoRedo管理.セルを追加する( cc );
2409 this.UndoRedo用GUIのEnabledを設定する();
2415 this.textBox説明_以前の値 = this.textBox説明.Text; // 以前の値 ← 現在の値
2416 UndoRedo.管理.UndoRedoした直後である = false;
2420 譜面.SSTFormatScore.Header.説明文 = this.textBox説明.Text;
2422 protected void textBox説明_Leave( object sender, EventArgs e )
2424 // 最新 UndoRedoセル の所有権を放棄する。
2425 this.UndoRedo管理.Undoするセルを取得して返す_見るだけ()?.所有権を放棄する( this.textBox説明 );
2427 protected string textBox説明_以前の値 = "";
2429 protected void textBoxメモ_TextChanged( object sender, EventArgs e )
2431 #region " この変更が Undo/Redo したことによるものではない場合、UndoRedoセルを追加or修正する。"
2433 if( !UndoRedo.管理.UndoRedoした直後である )
2437 UndoRedo.セルBase cell = this.UndoRedo管理.Undoするセルを取得して返す_見るだけ();
2439 if( ( cell != null ) && cell.所有権がある( this.textBoxメモ ) )
2441 // (Yes) 最新のセルの "変更後の値" を <現在の値> に更新。
2443 ( (UndoRedo.セル<string>) cell ).変更後の値 = this.textBoxメモ.Text;
2450 // "所有者ID" = 対象となるコンポーネントオブジェクト
2452 var cc = new UndoRedo.セル<string>(
2453 所有者ID: this.textBoxメモ,
2454 Undoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
2455 this.タブを選択する( タブ種別.基本情報 );
2456 this.numericUpDownメモ用小節番号.Value = (decimal) 任意1;
2457 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2458 this.textBoxメモ.Text = 変更前;
2459 this.textBoxメモ.Focus();
2461 int 小節番号 = (int) ( (decimal) 任意1 );
2463 #region " dicメモ の更新 "
2465 if( this.譜面.SSTFormatScore.dicメモ.ContainsKey( 小節番号 ) )
2467 if( string.IsNullOrEmpty( 変更前 ) )
2468 this.譜面.SSTFormatScore.dicメモ.Remove( 小節番号 );
2470 this.譜面.SSTFormatScore.dicメモ[ 小節番号 ] = 変更前;
2474 if( !string.IsNullOrEmpty( 変更前 ) )
2475 this.譜面.SSTFormatScore.dicメモ.Add( 小節番号, 変更前 );
2480 this.Act小節の先頭へ移動する( 小節番号 );
2481 this.splitContainer分割パネルコンテナ.Panel2.Refresh(); // 小節メモをリフレッシュ。
2483 Redoアクション: ( 変更対象, 変更前, 変更後, 任意1, 任意2 ) => {
2484 this.タブを選択する( タブ種別.基本情報 );
2485 this.numericUpDownメモ用小節番号.Value = (decimal) 任意1;
2486 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2487 this.textBoxメモ.Text = 変更後;
2488 this.textBoxメモ.Focus();
2490 int 小節番号 = (int) ( (decimal) 任意1 );
2492 #region " dicメモの更新 "
2494 if( this.譜面.SSTFormatScore.dicメモ.ContainsKey( 小節番号 ) )
2496 if( string.IsNullOrEmpty( 変更後 ) )
2497 this.譜面.SSTFormatScore.dicメモ.Remove( 小節番号 );
2499 this.譜面.SSTFormatScore.dicメモ[ 小節番号 ] = 変更後;
2503 if( !string.IsNullOrEmpty( 変更後 ) )
2504 this.譜面.SSTFormatScore.dicメモ.Add( 小節番号, 変更後 );
2509 this.Act小節の先頭へ移動する( 小節番号 );
2510 this.splitContainer分割パネルコンテナ.Panel2.Refresh(); // 小節メモをリフレッシュ。
2513 変更前の値: this.textBoxメモ_以前の値,
2514 変更後の値: this.textBoxメモ.Text,
2515 任意1: (object) this.numericUpDownメモ用小節番号.Value,
2518 this.UndoRedo管理.セルを追加する( cc );
2521 this.UndoRedo用GUIのEnabledを設定する();
2527 this.textBoxメモ_以前の値 = this.textBoxメモ.Text; // <以前の値> = <現在の値>
2529 if( false == UndoRedo.管理.UndoRedoした直後である )
2532 UndoRedo.管理.UndoRedoした直後である = false;
2534 #region " 小節番号に対応するメモを dicメモ に登録する。"
2537 int 小節番号 = (int) this.numericUpDownメモ用小節番号.Value;
2539 if( string.IsNullOrEmpty( this.textBoxメモ.Text ) )
2542 if( this.譜面.SSTFormatScore.dicメモ.ContainsKey( 小節番号 ) )
2543 this.譜面.SSTFormatScore.dicメモ.Remove( 小節番号 ); // 存在してたら削除。
2549 if( this.譜面.SSTFormatScore.dicメモ.ContainsKey( 小節番号 ) )
2550 this.譜面.SSTFormatScore.dicメモ[ 小節番号 ] = this.textBoxメモ.Text; // 存在してたら更新。
2552 this.譜面.SSTFormatScore.dicメモ.Add( 小節番号, this.textBoxメモ.Text ); // 存在してなかったら追加。
2557 #region " もし最終小節だったなら、後ろに4つ小節を加える。"
2560 int 小節番号 = (int) this.numericUpDownメモ用小節番号.Value;
2561 if( 小節番号 == this.譜面.SSTFormatScore.最大小節番号 )
2563 this.譜面.最後の小節の後ろに小節を4つ追加する();
2569 protected void textBoxメモ_Leave( object sender, EventArgs e )
2571 // 最新 UndoRedoセル の所有権を放棄する。
2572 this.UndoRedo管理.Undoするセルを取得して返す_見るだけ()?.所有権を放棄する( this.textBoxメモ );
2575 this.splitContainer分割パネルコンテナ.Panel2.Refresh();
2577 protected string textBoxメモ_以前の値 = "";
2579 protected void numericUpDownメモ用小節番号_ValueChanged( object sender, EventArgs e )
2581 // 小節番号にあわせて、textBoxメモにメモを表示する。
2582 int 小節番号 = (int) this.numericUpDownメモ用小節番号.Value;
2583 this.次のプロパティ変更がUndoRedoリストに載らないようにする();
2584 if( this.譜面.SSTFormatScore.dicメモ.ContainsKey( 小節番号 ) )
2585 this.textBoxメモ.Text = this.譜面.SSTFormatScore.dicメモ[ 小節番号 ];
2587 this.textBoxメモ.Text = "";
2588 this.次のプロパティ変更がUndoRedoリストに載るようにする();
2593 private Font メモ用フォント = new Font( FontFamily.GenericSansSerif, 9.0f );
2594 private readonly Dictionary<int, string> dic音量ラベル = new Dictionary<int, string>() {
2595 { 1, "1 (Smallest)" },
2596 { 2, "2 (Smaller)" },
2597 { 3, "3 (Middle)" },
2598 { 4, "4 (Normal)" },