protected void LoadBook(ScoreBook book) { LastExportCache = null; ScoreBook = book; OperationManager.Clear(); NoteView.Load(book.Score); InitializeScrollBar(book.Score.GetLastTick()); UpdateThumbHeight(); SetText(book.Path); if (!string.IsNullOrEmpty(book.Path)) { SoundSettings.Default.ScoreSounds.TryGetValue(book.Path, out CurrentSoundSource); } else { CurrentSoundSource = null; } }
public MainForm() { InitializeComponent(); Size = new Size(420, 700); Icon = Resources.MainIcon; AllowDrop = true; ToolStripManager.RenderMode = ToolStripManagerRenderMode.System; OperationManager = new OperationManager(); OperationManager.ChangesCommitted += (s, e) => SetText(ScoreBook.Path); OperationManager.OperationHistoryChanged += (s, e) => { SetText(ScoreBook.Path); NoteView.Invalidate(); }; NoteView = new NoteView(OperationManager) { Dock = DockStyle.Fill }; NoteViewScrollBar = new VScrollBar() { Dock = DockStyle.Right }; NoteViewScrollBar.ValueChanged += (s, e) => { NoteView.HeadTick = -NoteViewScrollBar.Value / 60 * 60; // 60の倍数できれいに表示されるので… NoteView.Invalidate(); }; NoteViewScrollBar.Scroll += (s, e) => { if (e.Type == ScrollEventType.EndScroll) { ExtendScrollBarRange(NoteViewScrollBar); } }; NoteView.Resize += (s, e) => UpdateThumbHeight(); NoteView.MouseWheel += (s, e) => { int value = NoteViewScrollBar.Value - e.Delta / 120 * NoteViewScrollBar.SmallChange; NoteViewScrollBar.Value = Math.Min(Math.Max(value, NoteViewScrollBar.Minimum), NoteViewScrollBar.GetMaximumValue()); ExtendScrollBarRange(NoteViewScrollBar); }; NoteView.DragScroll += (s, e) => { NoteViewScrollBar.Value = Math.Max(-NoteView.HeadTick, NoteViewScrollBar.Minimum); ExtendScrollBarRange(NoteViewScrollBar); }; void ExtendScrollBarRange(ScrollBar bar) { if (bar.Value < bar.Minimum * 0.9f) { bar.Minimum = (int)(NoteViewScrollBar.Minimum * 1.2); } } PreviewManager = new SoundPreviewManager(NoteView) { ClapSource = SoundSettings.Default.ClapSource }; PreviewManager.TickUpdated += (s, e) => Invoke((MethodInvoker)(() => NoteView.CurrentTick = e.Tick)); PreviewManager.ExceptionThrown += (s, e) => MessageBox.Show(this, "プレビュー中にエラーが発生しました。", Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Error); Menu = CreateMainMenu(); Controls.Add(NoteView); Controls.Add(NoteViewScrollBar); Controls.Add(CreateEditTargetToolStrip(NoteView)); Controls.Add(CreateMainToolStrip(NoteView)); NoteView.EditMode = EditMode.Edit; NoteView.EditTarget = EditTarget.Field; LoadEmptyBook(); if (!PreviewManager.IsSupported) { MessageBox.Show(this, "再生プレビューがサポートされていない環境です", Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Information); } if (PluginManager.FailedFiles.Count > 0) { string message = "以下のプラグインの読み込みに失敗しました。DLLファイルがブロックされているか無効なファイルである可能性があります。"; MessageBox.Show(this, string.Join("\n", new[] { message }.Concat(PluginManager.FailedFiles)), Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Warning); } }
private ToolStrip CreateEditTargetToolStrip(NoteView noteView) { var fieldButton = new ToolStripButton("フィールド", Resources.FieldIcon, (s, e) => noteView.EditTarget = EditTarget.Field) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var laneButton = new CheckableToolStripSplitButton() { DisplayStyle = ToolStripItemDisplayStyle.Image, Text = "レーン" }; laneButton.Click += (s, e) => noteView.EditTarget = EditTarget.Lane; laneButton.DropDown.Items.AddRange(new[] { new ToolStripMenuItem("赤レーン", Resources.RedLaneIcon, (s, e) => noteView.NewSurfaceLaneColor = Core.Track.SurfaceLaneColor.Red), new ToolStripMenuItem("緑レーン", Resources.GreenLaneIcon, (s, e) => noteView.NewSurfaceLaneColor = Core.Track.SurfaceLaneColor.Green), new ToolStripMenuItem("青レーン", Resources.BlueLaneIcon, (s, e) => noteView.NewSurfaceLaneColor = Core.Track.SurfaceLaneColor.Blue) }); laneButton.Image = Resources.RedLaneIcon; var noteButton = new CheckableToolStripSplitButton() { DisplayStyle = ToolStripItemDisplayStyle.Image, Text = "ノート" }; noteButton.Click += (s, e) => noteView.EditTarget = EditTarget.Note; noteButton.DropDown.Items.AddRange(new[] { new ToolStripMenuItem("TAP", Resources.TapIcon, (s, e) => noteView.NewNoteType = NewNoteType.Tap), new ToolStripMenuItem("HOLD", Resources.HoldIcon, (s, e) => noteView.NewNoteType = NewNoteType.Hold) }); noteButton.Image = Resources.TapIcon; var flickRightIcon = new Bitmap(Resources.FlickLeftIcon.Size.Width, Resources.FlickLeftIcon.Size.Height); using (var g = Graphics.FromImage(flickRightIcon)) { g.TranslateTransform(flickRightIcon.Width, 0); g.ScaleTransform(-1, 1); g.DrawImage(Resources.FlickLeftIcon, 0, 0); } var flickButton = new CheckableToolStripSplitButton() { DisplayStyle = ToolStripItemDisplayStyle.Image, Text = "フリック" }; flickButton.Click += (s, e) => noteView.EditTarget = EditTarget.Flick; flickButton.DropDown.Items.AddRange(new[] { new ToolStripMenuItem("左フリック", Resources.FlickLeftIcon, (s, e) => noteView.FlickDirection = HorizontalDirection.Left), new ToolStripMenuItem("右フリック", flickRightIcon, (s, e) => noteView.FlickDirection = HorizontalDirection.Right) }); flickButton.Image = Resources.FlickLeftIcon; var bellButton = new ToolStripButton("ベル", Resources.BellIcon, (s, e) => noteView.EditTarget = EditTarget.Bell) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var bulletButton = new ToolStripButton("敵弾", Resources.BulletIcon, (s, e) => noteView.EditTarget = EditTarget.Bullet) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var quantizeTicks = new int[] { 4, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192 }; var quantizeComboBox = new ToolStripComboBox("クォンタイズ") { DropDownStyle = ComboBoxStyle.DropDownList, AutoSize = false, Width = 80 }; quantizeComboBox.Items.AddRange(quantizeTicks.Select(p => p + "分").ToArray()); quantizeComboBox.Items.Add("カスタム"); quantizeComboBox.SelectedIndexChanged += (s, e) => { if (quantizeComboBox.SelectedIndex == quantizeComboBox.Items.Count - 1) { var form = new CustomQuantizeSelectionForm(noteView.Score.TicksPerBeat * 4); if (form.ShowDialog(this) == DialogResult.OK) { NoteView.QuantizeTick = form.QuantizeTick; } } else { noteView.QuantizeTick = noteView.TicksPerBeat * 4 / quantizeTicks[quantizeComboBox.SelectedIndex]; } noteView.Focus(); }; quantizeComboBox.SelectedIndex = 1; noteView.EditTargetChanged += (s, e) => { fieldButton.Checked = noteView.EditTarget == EditTarget.Field; laneButton.Checked = noteView.EditTarget == EditTarget.Lane; noteButton.Checked = noteView.EditTarget == EditTarget.Note; flickButton.Checked = noteView.EditTarget == EditTarget.Flick; bellButton.Checked = noteView.EditTarget == EditTarget.Bell; bulletButton.Checked = noteView.EditTarget == EditTarget.Bullet; }; noteView.NewSurfaceLaneColorChanged += (s, e) => { switch (noteView.NewSurfaceLaneColor) { case SurfaceLaneColor.Red: laneButton.Image = Resources.RedLaneIcon; break; case SurfaceLaneColor.Green: laneButton.Image = Resources.GreenLaneIcon; break; case SurfaceLaneColor.Blue: laneButton.Image = Resources.BlueLaneIcon; break; } }; noteView.NewNoteTypeChanged += (s, e) => { noteButton.Image = noteView.NewNoteType == NewNoteType.Tap ? Resources.TapIcon : Resources.HoldIcon; }; noteView.FlickDirectionChanged += (s, e) => { flickButton.Image = noteView.FlickDirection == HorizontalDirection.Left ? Resources.FlickLeftIcon : flickRightIcon; }; return(new ToolStrip(new ToolStripItem[] { fieldButton, laneButton, noteButton, flickButton, bellButton, bulletButton, quantizeComboBox })); }
private ToolStrip CreateMainToolStrip(NoteView noteView) { var newFileButton = new ToolStripButton("新規作成", Resources.NewIcon, (s, e) => Clear()) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var openFileButton = new ToolStripButton("開く", Resources.OpenIcon, (s, e) => OpenFile()) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var saveFileButton = new ToolStripButton("上書き保存", Resources.SaveIcon, (s, e) => SaveFile()) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var exportButton = new ToolStripButton("エクスポート", Resources.ExportIcon, (s, e) => { if (LastExportCache == null) { return; } if (!ExportFile(LastExportCache)) { return; } MessageBox.Show(this, "再エクスポートが完了しました。", Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Information); }) { DisplayStyle = ToolStripItemDisplayStyle.Image, Enabled = false }; var undoButton = new ToolStripButton("元に戻す", Resources.UndoIcon, (s, e) => OperationManager.Undo()) { DisplayStyle = ToolStripItemDisplayStyle.Image, Enabled = false }; var redoButton = new ToolStripButton("やり直す", Resources.RedoIcon, (s, e) => OperationManager.Redo()) { DisplayStyle = ToolStripItemDisplayStyle.Image, Enabled = false }; var penButton = new ToolStripButton("ペン", Resources.EditIcon, (s, e) => noteView.EditMode = EditMode.Edit) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var selectionButton = new ToolStripButton("選択", Resources.SelectionIcon, (s, e) => noteView.EditMode = EditMode.Select) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var eraserButton = new ToolStripButton("消しゴム", Resources.EraserIcon, (s, e) => noteView.EditMode = EditMode.Erase) { DisplayStyle = ToolStripItemDisplayStyle.Image }; LastExportCacheChanged += (s, e) => exportButton.Enabled = LastExportCache != null; OperationManager.OperationHistoryChanged += (s, e) => { undoButton.Enabled = OperationManager.CanUndo; redoButton.Enabled = OperationManager.CanRedo; }; noteView.EditModeChanged += (s, e) => { penButton.Checked = noteView.EditMode == EditMode.Edit; selectionButton.Checked = noteView.EditMode == EditMode.Select; eraserButton.Checked = noteView.EditMode == EditMode.Erase; }; return(new ToolStrip(new ToolStripItem[] { newFileButton, openFileButton, saveFileButton, exportButton, new ToolStripSeparator(), undoButton, redoButton, new ToolStripSeparator(), penButton, selectionButton, eraserButton })); }
private MainMenu CreateMainMenu() { var bookPropertiesItem = new MenuItem("譜面プロパティ(&P)", (s, e) => { var form = new BookPropertiesForm(ScoreBook, CurrentSoundSource); if (form.ShowDialog(this) != DialogResult.OK) { return; } ScoreBook.Title = form.Title; ScoreBook.ArtistName = form.ArtistName; ScoreBook.NotesDesignerName = form.NotesDesignerName; CurrentSoundSource = form.SoundSource; }); var exportPluginItems = PluginManager.ScoreBookExportPlugins.Select(p => new MenuItem(p.DisplayName, (s, e) => { var dialog = new SaveFileDialog() { Filter = p.Filter, Title = "エクスポート先選択" }; if (dialog.ShowDialog(this) != DialogResult.OK) { return; } var args = new ScoreBookExportPluginArgs(() => ScoreBook.Clone()) { OutputPath = dialog.FileName }; ExportFile(new Exporter(p, args)); })); var fileMenuItems = new MenuItem[] { new MenuItem("新規作成(&N)", (s, e) => Clear()) { Shortcut = Shortcut.CtrlN }, new MenuItem("開く(&O)", (s, e) => OpenFile()) { Shortcut = Shortcut.CtrlO }, new MenuItem("保存(&S)", (s, e) => SaveFile()) { Shortcut = Shortcut.CtrlS }, new MenuItem("名前をつけて保存(&A)", (s, e) => SaveAs()) { Shortcut = Shortcut.CtrlShiftS }, new MenuItem("-"), new MenuItem("エクスポート(&E)", exportPluginItems.ToArray()), new MenuItem("-"), bookPropertiesItem, new MenuItem("-"), new MenuItem("終了(&X)", (s, e) => Close()) }; var undoItem = new MenuItem("元に戻す", (s, e) => OperationManager.Undo()) { Shortcut = Shortcut.CtrlZ, Enabled = false }; var redoItem = new MenuItem("やり直す", (s, e) => OperationManager.Redo()) { Shortcut = Shortcut.CtrlY, Enabled = false }; var removeEventsItem = new MenuItem("選択範囲内イベントを削除", (s, e) => { int head = NoteView.SelectedRange.StartTick + (NoteView.SelectedRange.Duration < 0 ? NoteView.SelectedRange.Duration : 0); int tail = NoteView.SelectedRange.StartTick + (NoteView.SelectedRange.Duration < 0 ? 0 : NoteView.SelectedRange.Duration); IEnumerable <IOperation> RemoveFilter <T>(List <T> list) where T: EventBase { return(list.Where(p => p.Tick != 0 && p.Tick >= head && p.Tick <= tail).Select(p => new RemoveEventOperation <T>(p, list))); } var events = NoteView.Score.Events; var ops = new[] { RemoveFilter(events.BPMChangeEvents), RemoveFilter(events.TimeSignatureChangeEvents), RemoveFilter(events.HighSpeedChangeEvents) }.SelectMany(p => p); OperationManager.ExecuteAndPush(new CompositeOperation("イベント削除", ops.ToArray())); }); var editMenuItems = new MenuItem[] { undoItem, redoItem, new MenuItem("-"), removeEventsItem }; var previewItem = new MenuItem("譜面プレビュー", (s, e) => { IsPreviewMode = !IsPreviewMode; ((MenuItem)s).Checked = IsPreviewMode; }, Shortcut.CtrlP); var viewMenuItems = new MenuItem[] { previewItem }; var addBpmItem = new MenuItem("BPM", (s, e) => { var form = new BPMSelectionForm() { BPM = NoteView.Score.Events.BPMChangeEvents.OrderBy(p => p.Tick).LastOrDefault(p => p.Tick <= NoteView.CurrentTick)?.BPM ?? 120m }; if (form.ShowDialog(this) != DialogResult.OK) { return; } var item = new BPMChangeEvent() { Tick = NoteView.CurrentTick, BPM = form.BPM }; IOperation op = ProcessAddEvent(item, NoteView.Score.Events.BPMChangeEvents); OperationManager.ExecuteAndPush(op); NoteView.Invalidate(); }); var addTimeSignatureItem = new MenuItem("拍子", (s, e) => { var form = new TimesignatureSelectionForm(); if (form.ShowDialog(this) != DialogResult.OK) { return; } var item = new TimeSignatureChangeEvent() { Tick = NoteView.CurrentTick, Numerator = form.Numerator, DenominatorExponent = form.DenominatorExponent }; IOperation op = ProcessAddEvent(item, NoteView.Score.Events.TimeSignatureChangeEvents); OperationManager.ExecuteAndPush(op); NoteView.Invalidate(); }); var addHighSpeedItem = new MenuItem("ハイスピード", (s, e) => { var form = new HighSpeedSelectionForm() { SpeedRatio = NoteView.Score.Events.HighSpeedChangeEvents.OrderBy(p => p.Tick).LastOrDefault(p => p.Tick <= NoteView.CurrentTick)?.SpeedRatio ?? 1.0m }; if (form.ShowDialog(this) != DialogResult.OK) { return; } var item = new HighSpeedChangeEvent() { Tick = NoteView.CurrentTick, SpeedRatio = form.SpeedRatio }; IOperation op = ProcessAddEvent(item, NoteView.Score.Events.HighSpeedChangeEvents); OperationManager.ExecuteAndPush(op); NoteView.Invalidate(); }); IOperation ProcessAddEvent <T>(T item, List <T> list) where T : EventBase { var prev = list.SingleOrDefault(p => p.Tick == item.Tick); var addOp = new AddEventOperation <T>(item, list); if (prev == null) { return(addOp); } var removeOp = new RemoveEventOperation <T>(prev, list); return(new CompositeOperation(addOp.Description, new IOperation[] { removeOp, addOp })); } var insertMenuItems = new MenuItem[] { addBpmItem, addTimeSignatureItem, addHighSpeedItem }; var previewOnlyNotesItem = new MenuItem("ベル/敵弾でガイド音を鳴らさない", (s, e) => { var item = s as MenuItem; item.Checked = !item.Checked; ApplicationSettings.Default.PreviewOnlyNotes = item.Checked; }) { Checked = ApplicationSettings.Default.PreviewOnlyNotes }; var playItem = new MenuItem("再生/停止", (s, e) => { if (PreviewManager.Playing) { PreviewManager.Stop(); return; } if (CurrentSoundSource == null) { MessageBox.Show(this, "プレビュー用音源ファイルが設定されていません。", Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } if (!File.Exists(CurrentSoundSource.FilePath)) { MessageBox.Show(this, "プレビュー用音源ファイルが見つかりません。", Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } int startTick = NoteView.CurrentTick; EventHandler lambda = null; lambda = (p, q) => { previewOnlyNotesItem.Enabled = true; PreviewManager.Finished -= lambda; NoteView.CurrentTick = startTick; NoteView.Editable = CanEdit; }; try { var score = NoteView.Restore(); PreviewManager.TicksPerBeat = score.TicksPerBeat; if (!PreviewManager.Start(score, CurrentSoundSource, startTick, ApplicationSettings.Default.PreviewOnlyNotes)) { return; } previewOnlyNotesItem.Enabled = false; PreviewManager.Finished += lambda; NoteView.Editable = CanEdit; } catch (Exception ex) { Program.DumpExceptionTo(ex, "sound_exception.json"); PreviewManager.Stop(); } }, (Shortcut)Keys.Space); var playMenuItems = new MenuItem[] { playItem, new MenuItem("-"), previewOnlyNotesItem }; var helpMenuItems = new MenuItem[] { new MenuItem("Wikiを開く", (s, e) => System.Diagnostics.Process.Start("https://github.com/paralleltree/Yuzu/wiki"), Shortcut.F1), new MenuItem("バージョン情報", (s, e) => new VersionInfoForm().ShowDialog(this)) }; OperationManager.OperationHistoryChanged += (s, e) => { undoItem.Enabled = OperationManager.CanUndo; redoItem.Enabled = OperationManager.CanRedo; }; return(new MainMenu(new MenuItem[] { new MenuItem("ファイル(&F)", fileMenuItems), new MenuItem("編集(&E)", editMenuItems), new MenuItem("表示(&V)", viewMenuItems), new MenuItem("挿入(&I)", insertMenuItems), new MenuItem("再生(&P)", playMenuItems), new MenuItem("ヘルプ(&H)", helpMenuItems) })); }
protected void CommitChanges() { ScoreBook.Score = NoteView.Restore(); }