public SoundPreviewManager(NoteView noteView) { ClapSource = new SoundSource("guide.mp3", 0.036); NoteView = noteView; Timer.Tick += Tick; SoundManager.ExceptionThrown += (s, e) => noteView.InvokeIfRequired(() => { Stop(); ExceptionThrown?.Invoke(this, EventArgs.Empty); }); }
protected void LoadBook(ScoreBook book) { ScoreBook = book; NoteView.LoadScore(book.Score); NoteViewScrollBar.Value = NoteViewScrollBar.GetMaximumValue(); NoteViewScrollBar.Minimum = -Math.Max(NoteView.UnitBeatTick * 4 * 20, NoteView.Notes.GetLastTick()); UpdateThumbHeight(); SetText(book.Path); LastExportData = null; if (!string.IsNullOrEmpty(book.Path)) { SoundConfiguration.Default.ScoreSound.TryGetValue(book.Path, out CurrentMusicSource); } else { CurrentMusicSource = null; } }
protected void LoadBook(ScoreBook book) { ScoreBook = book; OperationManager.Clear(); NoteView.Initialize(book.Score); NoteViewScrollBar.Value = NoteViewScrollBar.GetMaximumValue(); NoteViewScrollBar.Minimum = -Math.Max(NoteView.UnitBeatTick * 4 * 20, NoteView.Notes.GetLastTick()); NoteViewScrollBar.SmallChange = NoteView.UnitBeatTick; UpdateThumbHeight(); SetText(book.Path); LastExportData = null; if (!string.IsNullOrEmpty(book.Path)) { SoundSettings.Default.ScoreSound.TryGetValue(book.Path, out CurrentMusicSource); } else { CurrentMusicSource = null; } }
private ToolStrip CreateNewNoteTypeToolStrip(NoteView noteView) { var tapButton = new ToolStripButton("TAP", Resources.TapIcon, (s, e) => noteView.NewNoteType = NoteType.Tap) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var exTapButton = new ToolStripButton("ExTAP", Resources.ExTapIcon, (s, e) => noteView.NewNoteType = NoteType.ExTap) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var holdButton = new ToolStripButton("HOLD", Resources.HoldIcon, (s, e) => noteView.NewNoteType = NoteType.Hold) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var slideButton = new ToolStripButton("SLIDE", Resources.SlideIcon, (s, e) => { noteView.NewNoteType = NoteType.Slide; noteView.IsNewSlideStepVisible = false; }) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var slideStepButton = new ToolStripButton(MainFormStrings.SlideStep, Resources.SlideStepIcon, (s, e) => { noteView.NewNoteType = NoteType.Slide; noteView.IsNewSlideStepVisible = true; }) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var airActionButton = new ToolStripButton("AIR-ACTION", Resources.AirActionIcon, (s, e) => noteView.NewNoteType = NoteType.AirAction) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var flickButton = new ToolStripButton("FLICK", Resources.FlickIcon, (s, e) => noteView.NewNoteType = NoteType.Flick) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var damageButton = new ToolStripButton("DAMAGE", Resources.DamgeIcon, (s, e) => noteView.NewNoteType = NoteType.Damage) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var airKind = new CheckableToolStripSplitButton() { DisplayStyle = ToolStripItemDisplayStyle.Image }; airKind.Text = "AIR"; airKind.Click += (s, e) => noteView.NewNoteType = NoteType.Air; airKind.DropDown.Items.AddRange(new ToolStripItem[] { new ToolStripMenuItem(MainFormStrings.AirUp, Resources.AirUpIcon, (s, e) => noteView.AirDirection = new AirDirection(VerticalAirDirection.Up, HorizontalAirDirection.Center)), new ToolStripMenuItem(MainFormStrings.AirLeftUp, Resources.AirLeftUpIcon, (s, e) => noteView.AirDirection = new AirDirection(VerticalAirDirection.Up, HorizontalAirDirection.Left)), new ToolStripMenuItem(MainFormStrings.AirRightUp, Resources.AirRightUpIcon, (s, e) => noteView.AirDirection = new AirDirection(VerticalAirDirection.Up, HorizontalAirDirection.Right)), new ToolStripMenuItem(MainFormStrings.AirDown, Resources.AirDownIcon, (s, e) => noteView.AirDirection = new AirDirection(VerticalAirDirection.Down, HorizontalAirDirection.Center)), new ToolStripMenuItem(MainFormStrings.AirLeftDown, Resources.AirLeftDownIcon, (s, e) => noteView.AirDirection = new AirDirection(VerticalAirDirection.Down, HorizontalAirDirection.Left)), new ToolStripMenuItem(MainFormStrings.AirRightDown, Resources.AirRightDownIcon, (s, e) => noteView.AirDirection = new AirDirection(VerticalAirDirection.Down, HorizontalAirDirection.Right)) }); airKind.Image = Resources.AirUpIcon; 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 + MainFormStrings.Division).ToArray()); quantizeComboBox.Items.Add(MainFormStrings.Custom); quantizeComboBox.SelectedIndexChanged += (s, e) => { if (quantizeComboBox.SelectedIndex == quantizeComboBox.Items.Count - 1) { // ユーザー定義 var form = new CustomQuantizeSelectionForm(ScoreBook.Score.TicksPerBeat * 4); if (form.ShowDialog(this) == DialogResult.OK) { noteView.QuantizeTick = form.QuantizeTick; } } else { noteView.QuantizeTick = noteView.UnitBeatTick * 4 / quantizeTicks[quantizeComboBox.SelectedIndex]; } noteView.Focus(); }; quantizeComboBox.SelectedIndex = 1; noteView.NewNoteTypeChanged += (s, e) => { tapButton.Checked = noteView.NewNoteType.HasFlag(NoteType.Tap); exTapButton.Checked = noteView.NewNoteType.HasFlag(NoteType.ExTap); holdButton.Checked = noteView.NewNoteType.HasFlag(NoteType.Hold); slideButton.Checked = noteView.NewNoteType.HasFlag(NoteType.Slide) && !noteView.IsNewSlideStepVisible; slideStepButton.Checked = noteView.NewNoteType.HasFlag(NoteType.Slide) && noteView.IsNewSlideStepVisible; airKind.Checked = noteView.NewNoteType.HasFlag(NoteType.Air); airActionButton.Checked = noteView.NewNoteType.HasFlag(NoteType.AirAction); flickButton.Checked = noteView.NewNoteType.HasFlag(NoteType.Flick); damageButton.Checked = noteView.NewNoteType.HasFlag(NoteType.Damage); }; noteView.AirDirectionChanged += (s, e) => { switch (noteView.AirDirection.HorizontalDirection) { case HorizontalAirDirection.Center: airKind.Image = noteView.AirDirection.VerticalDirection == VerticalAirDirection.Up ? Resources.AirUpIcon : Resources.AirDownIcon; break; case HorizontalAirDirection.Left: airKind.Image = noteView.AirDirection.VerticalDirection == VerticalAirDirection.Up ? Resources.AirLeftUpIcon : Resources.AirLeftDownIcon; break; case HorizontalAirDirection.Right: airKind.Image = noteView.AirDirection.VerticalDirection == VerticalAirDirection.Up ? Resources.AirRightUpIcon : Resources.AirRightDownIcon; break; } }; return(new ToolStrip(new ToolStripItem[] { tapButton, exTapButton, holdButton, slideButton, slideStepButton, airKind, airActionButton, flickButton, damageButton, quantizeComboBox })); }
public MainForm() { InitializeComponent(); Size = new Size(420, 700); Icon = Resources.MainIcon; ToolStripManager.RenderMode = ToolStripManagerRenderMode.System; OperationManager = new OperationManager(); OperationManager.OperationHistoryChanged += (s, e) => { SetText(ScoreBook.Path); NoteView.Invalidate(); }; OperationManager.ChangesCommitted += (s, e) => SetText(ScoreBook.Path); NoteView = new NoteView(OperationManager) { Dock = DockStyle.Fill, UnitBeatHeight = ApplicationSettings.Default.UnitBeatHeight, UnitLaneWidth = ApplicationSettings.Default.UnitLaneWidth, InsertAirWithAirAction = ApplicationSettings.Default.InsertAirWithAirAction }; PreviewManager = new SoundPreviewManager(this); PreviewManager.IsStopAtLastNote = ApplicationSettings.Default.IsPreviewAbortAtLastNote; PreviewManager.TickUpdated += (s, e) => NoteView.CurrentTick = e.Tick; PreviewManager.ExceptionThrown += (s, e) => MessageBox.Show(this, ErrorStrings.PreviewException, Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Error); NoteViewScrollBar = new VScrollBar() { Dock = DockStyle.Right, Minimum = -NoteView.UnitBeatTick * 4 * 20, SmallChange = NoteView.UnitBeatTick }; void processScrollBarRangeExtension(ScrollBar s) { if (NoteViewScrollBar.Value < NoteViewScrollBar.Minimum * 0.9f) { NoteViewScrollBar.Minimum = (int)(NoteViewScrollBar.Minimum * 1.2); } } 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()); processScrollBarRangeExtension(NoteViewScrollBar); }; NoteView.DragScroll += (s, e) => { NoteViewScrollBar.Value = Math.Max(-NoteView.HeadTick, NoteViewScrollBar.Minimum); processScrollBarRangeExtension(NoteViewScrollBar); }; NoteViewScrollBar.ValueChanged += (s, e) => { NoteView.HeadTick = -NoteViewScrollBar.Value / 60 * 60; // 60の倍数できれいに表示されるので… NoteView.Invalidate(); }; NoteViewScrollBar.Scroll += (s, e) => { if (e.Type == ScrollEventType.EndScroll) { processScrollBarRangeExtension(NoteViewScrollBar); } }; NoteView.NewNoteTypeChanged += (s, e) => NoteView.EditMode = EditMode.Edit; AllowDrop = true; DragEnter += (s, e) => { e.Effect = DragDropEffects.None; if (e.Data.GetDataPresent(DataFormats.FileDrop)) { var items = (string[])e.Data.GetData(DataFormats.FileDrop); if (items.Length == 1 && items.All(p => Path.GetExtension(p) == FileExtension && File.Exists(p))) { e.Effect = DragDropEffects.Copy; } } }; DragDrop += (s, e) => { string path = ((string[])e.Data.GetData(DataFormats.FileDrop)).Single(); if (!ConfirmDiscardChanges()) { return; } LoadFile(path); }; FormClosing += (s, e) => { if (!ConfirmDiscardChanges()) { e.Cancel = true; return; } ApplicationSettings.Default.Save(); }; using (var manager = this.WorkWithLayout()) { this.Menu = CreateMainMenu(NoteView); this.Controls.Add(NoteView); this.Controls.Add(NoteViewScrollBar); this.Controls.Add(CreateNewNoteTypeToolStrip(NoteView)); this.Controls.Add(CreateMainToolStrip(NoteView)); } NoteView.NewNoteType = NoteType.Tap; NoteView.EditMode = EditMode.Edit; LoadEmptyBook(); SetText(); if (!PreviewManager.IsSupported) { MessageBox.Show(this, ErrorStrings.PreviewNotSupported, Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Information); } if (PluginManager.FailedFiles.Count > 0) { MessageBox.Show(this, string.Join("\n", new[] { ErrorStrings.PluginLoadError }.Concat(PluginManager.FailedFiles)), Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Warning); } if (PluginManager.InvalidFiles.Count > 0) { MessageBox.Show(this, string.Join("\n", new[] { ErrorStrings.PluginNotSupported }.Concat(PluginManager.InvalidFiles)), Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Error); } }
private ToolStrip CreateMainToolStrip(NoteView noteView) { var newFileButton = new ToolStripButton(MainFormStrings.NewFile, Resources.NewFileIcon, (s, e) => ClearFile()) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var openFileButton = new ToolStripButton(MainFormStrings.OpenFile, Resources.OpenFileIcon, (s, e) => OpenFile()) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var saveFileButton = new ToolStripButton(MainFormStrings.SaveFile, Resources.SaveFileIcon, (s, e) => SaveFile()) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var exportButton = new ToolStripButton(MainFormStrings.Export, Resources.ExportIcon, (s, e) => { if (!ExportManager.CanReExport) { if (PluginManager.ScoreBookExportPlugins.Count() == 1) { ExportAs(PluginManager.ScoreBookExportPlugins.Single()); return; } MessageBox.Show(this, ErrorStrings.NotExported, Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Information); return; } HandleExport(ScoreBook, ExportManager.PrepareReExport()); }) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var cutButton = new ToolStripButton(MainFormStrings.Cut, Resources.CutIcon, (s, e) => noteView.CutSelectedNotes()) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var copyButton = new ToolStripButton(MainFormStrings.Copy, Resources.CopyIcon, (s, e) => noteView.CopySelectedNotes()) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var pasteButton = new ToolStripButton(MainFormStrings.Paste, Resources.PasteIcon, (s, e) => noteView.PasteNotes()) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var undoButton = new ToolStripButton(MainFormStrings.Undo, Resources.UndoIcon, (s, e) => OperationManager.Undo()) { DisplayStyle = ToolStripItemDisplayStyle.Image, Enabled = false }; var redoButton = new ToolStripButton(MainFormStrings.Redo, Resources.RedoIcon, (s, e) => OperationManager.Redo()) { DisplayStyle = ToolStripItemDisplayStyle.Image, Enabled = false }; var penButton = new ToolStripButton(MainFormStrings.Pen, Resources.EditIcon, (s, e) => noteView.EditMode = EditMode.Edit) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var selectionButton = new ToolStripButton(MainFormStrings.Selection, Resources.SelectionIcon, (s, e) => noteView.EditMode = EditMode.Select) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var eraserButton = new ToolStripButton(MainFormStrings.Eraser, Resources.EraserIcon, (s, e) => noteView.EditMode = EditMode.Erase) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var zoomInButton = new ToolStripButton(MainFormStrings.ZoomIn, Resources.ZoomInIcon) { Enabled = noteView.UnitBeatHeight < 1920, DisplayStyle = ToolStripItemDisplayStyle.Image }; var zoomOutButton = new ToolStripButton(MainFormStrings.ZoomOut, Resources.ZoomOutIcon) { Enabled = noteView.UnitBeatHeight > 30, DisplayStyle = ToolStripItemDisplayStyle.Image }; zoomInButton.Click += (s, e) => { noteView.UnitBeatHeight *= 2; ApplicationSettings.Default.UnitBeatHeight = (int)noteView.UnitBeatHeight; zoomOutButton.Enabled = CanZoomOut; zoomInButton.Enabled = CanZoomIn; UpdateThumbHeight(); }; zoomOutButton.Click += (s, e) => { noteView.UnitBeatHeight /= 2; ApplicationSettings.Default.UnitBeatHeight = (int)noteView.UnitBeatHeight; zoomInButton.Enabled = CanZoomIn; zoomOutButton.Enabled = CanZoomOut; UpdateThumbHeight(); }; ZoomInButton = zoomInButton; ZoomOutButton = zoomOutButton; OperationManager.OperationHistoryChanged += (s, e) => { undoButton.Enabled = OperationManager.CanUndo; redoButton.Enabled = OperationManager.CanRedo; }; noteView.EditModeChanged += (s, e) => { selectionButton.Checked = noteView.EditMode == EditMode.Select; penButton.Checked = noteView.EditMode == EditMode.Edit; eraserButton.Checked = noteView.EditMode == EditMode.Erase; }; return(new ToolStrip(new ToolStripItem[] { newFileButton, openFileButton, saveFileButton, exportButton, new ToolStripSeparator(), cutButton, copyButton, pasteButton, new ToolStripSeparator(), undoButton, redoButton, new ToolStripSeparator(), penButton, selectionButton, eraserButton, new ToolStripSeparator(), zoomInButton, zoomOutButton })); }
private MainMenu CreateMainMenu(NoteView noteView) { var importPluginItems = PluginManager.ScoreBookImportPlugins.Select(p => new MenuItem(p.DisplayName, (s, e) => { if (!ConfirmDiscardChanges()) { return; } if (!TrySelectOpeningFile(p.FileFilter, out string path)) { return; } using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read)) { var args = new ScoreBookImportPluginArgs(stream); HandleImport(p, args); } })).ToArray(); var exportPluginItems = PluginManager.ScoreBookExportPlugins.Select(p => new MenuItem(p.DisplayName, (s, e) => { ExportAs(p); })).ToArray(); var bookPropertiesMenuItem = new MenuItem(MainFormStrings.BookProperty, (s, e) => { var vm = new BookPropertiesWindowViewModel(ScoreBook, CurrentMusicSource); var window = new BookPropertiesWindow() { DataContext = vm }; window.ShowDialog(this); }); var fileMenuItems = new MenuItem[] { new MenuItem(MainFormStrings.NewFile + "(&N)", (s, e) => ClearFile()) { Shortcut = Shortcut.CtrlN }, new MenuItem(MainFormStrings.OpenFile + "(&O)", (s, e) => OpenFile()) { Shortcut = Shortcut.CtrlO }, new MenuItem(MainFormStrings.SaveFile + "(&S)", (s, e) => SaveFile()) { Shortcut = Shortcut.CtrlS }, new MenuItem(MainFormStrings.SaveAs + "(&A)", (s, e) => SaveAs()) { Shortcut = Shortcut.CtrlShiftS }, new MenuItem("-"), new MenuItem(MainFormStrings.Import, importPluginItems) { Enabled = importPluginItems.Length > 0 }, new MenuItem(MainFormStrings.Export, exportPluginItems) { Enabled = exportPluginItems.Length > 0 }, new MenuItem("-"), bookPropertiesMenuItem, new MenuItem("-"), new MenuItem(MainFormStrings.Exit + "(&X)", (s, e) => this.Close()) }; var undoItem = new MenuItem(MainFormStrings.Undo, (s, e) => OperationManager.Undo()) { Shortcut = Shortcut.CtrlZ, Enabled = false }; var redoItem = new MenuItem(MainFormStrings.Redo, (s, e) => OperationManager.Redo()) { Shortcut = Shortcut.CtrlY, Enabled = false }; var cutItem = new MenuItem(MainFormStrings.Cut, (s, e) => noteView.CutSelectedNotes(), Shortcut.CtrlX); var copyItem = new MenuItem(MainFormStrings.Copy, (s, e) => noteView.CopySelectedNotes(), Shortcut.CtrlC); var pasteItem = new MenuItem(MainFormStrings.Paste, (s, e) => noteView.PasteNotes(), Shortcut.CtrlV); var pasteFlippedItem = new MenuItem(MainFormStrings.PasteFlipped, (s, e) => noteView.PasteFlippedNotes(), Shortcut.CtrlShiftV); var selectAllItem = new MenuItem(MainFormStrings.SelectAll, (s, e) => noteView.SelectAll(), Shortcut.CtrlA); var selectToEndItem = new MenuItem(MainFormStrings.SelectToEnd, (s, e) => noteView.SelectToEnd()); var selectoToBeginningItem = new MenuItem(MainFormStrings.SelectToBeginning, (s, e) => noteView.SelectToBeginning()); var flipSelectedNotesItem = new MenuItem(MainFormStrings.FlipSelectedNotes, (s, e) => noteView.FlipSelectedNotes()); var removeSelectedNotesItem = new MenuItem(MainFormStrings.RemoveSelectedNotes, (s, e) => noteView.RemoveSelectedNotes(), Shortcut.Del); var removeEventsItem = new MenuItem(MainFormStrings.RemoveEvents, (s, e) => { int minTick = noteView.SelectedRange.StartTick + (noteView.SelectedRange.Duration < 0 ? noteView.SelectedRange.Duration : 0); int maxTick = noteView.SelectedRange.StartTick + (noteView.SelectedRange.Duration < 0 ? 0 : noteView.SelectedRange.Duration); bool isContained(EventBase p) => p.Tick != 0 && minTick <= p.Tick && maxTick >= p.Tick; var events = ScoreBook.Score.Events; var bpmOp = events.BpmChangeEvents.Where(p => isContained(p)).ToList().Select(p => { ScoreBook.Score.Events.BpmChangeEvents.Remove(p); return(new RemoveEventOperation <BpmChangeEvent>(events.BpmChangeEvents, p)); }).ToList(); var speedOp = events.HighSpeedChangeEvents.Where(p => isContained(p)).ToList().Select(p => { ScoreBook.Score.Events.HighSpeedChangeEvents.Remove(p); return(new RemoveEventOperation <HighSpeedChangeEvent>(events.HighSpeedChangeEvents, p)); }).ToList(); var signatureOp = events.TimeSignatureChangeEvents.Where(p => isContained(p)).ToList().Select(p => { ScoreBook.Score.Events.TimeSignatureChangeEvents.Remove(p); return(new RemoveEventOperation <TimeSignatureChangeEvent>(events.TimeSignatureChangeEvents, p)); }).ToList(); OperationManager.Push(new CompositeOperation("イベント削除", bpmOp.Cast <IOperation>().Concat(speedOp).Concat(signatureOp))); noteView.Invalidate(); }); var insertAirWithAirActionItem = new MenuItem(MainFormStrings.InsertAirWithAirAction, (s, e) => { var item = s as MenuItem; item.Checked = !item.Checked; NoteView.InsertAirWithAirAction = item.Checked; ApplicationSettings.Default.InsertAirWithAirAction = item.Checked; }) { Checked = ApplicationSettings.Default.InsertAirWithAirAction }; var pluginItems = PluginManager.ScorePlugins.Select(p => new MenuItem(p.DisplayName, (s, e) => { CommitChanges(); void updateScore(Score newScore) { var op = new UpdateScoreOperation(ScoreBook.Score, newScore, score => { ScoreBook.Score = score; noteView.UpdateScore(score); }); OperationManager.InvokeAndPush(op); } try { p.Run(new ScorePluginArgs(() => ScoreBook.Score.Clone(), noteView.SelectedRange, updateScore)); } catch (Exception ex) { Program.DumpExceptionTo(ex, "plugin_exception.json"); MessageBox.Show(this, ErrorStrings.PluginException, Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Error); } })).ToArray(); var pluginItem = new MenuItem(MainFormStrings.Plugin, pluginItems) { Enabled = pluginItems.Length > 0 }; var editMenuItems = new MenuItem[] { undoItem, redoItem, new MenuItem("-"), cutItem, copyItem, pasteItem, pasteFlippedItem, new MenuItem("-"), selectAllItem, selectToEndItem, selectoToBeginningItem, new MenuItem("-"), flipSelectedNotesItem, removeSelectedNotesItem, removeEventsItem, new MenuItem("-"), insertAirWithAirActionItem, new MenuItem("-"), pluginItem }; var viewModeItem = new MenuItem(MainFormStrings.ScorePreview, (s, e) => { IsPreviewMode = !IsPreviewMode; ((MenuItem)s).Checked = IsPreviewMode; }, Shortcut.CtrlP); WidenLaneWidthMenuItem = new MenuItem(MainFormStrings.WidenLaneWidth); NarrowLaneWidthMenuItem = new MenuItem(MainFormStrings.NarrowLaneWidth); WidenLaneWidthMenuItem.Click += (s, e) => { noteView.UnitLaneWidth += 4; ApplicationSettings.Default.UnitLaneWidth = noteView.UnitLaneWidth; WidenLaneWidthMenuItem.Enabled = CanWidenLaneWidth; NarrowLaneWidthMenuItem.Enabled = CanNarrowLaneWidth; }; NarrowLaneWidthMenuItem.Click += (s, e) => { noteView.UnitLaneWidth -= 4; ApplicationSettings.Default.UnitLaneWidth = noteView.UnitLaneWidth; WidenLaneWidthMenuItem.Enabled = CanWidenLaneWidth; NarrowLaneWidthMenuItem.Enabled = CanNarrowLaneWidth; }; var viewMenuItems = new MenuItem[] { viewModeItem, new MenuItem("-"), WidenLaneWidthMenuItem, NarrowLaneWidthMenuItem }; void UpdateEvent <T>(List <T> list, T item) where T : EventBase { var prev = list.SingleOrDefault(p => p.Tick == item.Tick); var insertOp = new InsertEventOperation <T>(list, item); if (prev == null) { OperationManager.InvokeAndPush(insertOp); } else { var removeOp = new RemoveEventOperation <T>(list, prev); OperationManager.InvokeAndPush(new CompositeOperation(insertOp.Description, new IOperation[] { removeOp, insertOp })); } noteView.Invalidate(); } var insertBpmItem = new MenuItem("BPM", (s, e) => { var form = new BpmSelectionForm() { Bpm = noteView.ScoreEvents.BpmChangeEvents.OrderBy(p => p.Tick).LastOrDefault(p => p.Tick <= noteView.CurrentTick)?.Bpm ?? 120 }; if (form.ShowDialog(this) != DialogResult.OK) { return; } var item = new BpmChangeEvent() { Tick = noteView.CurrentTick, Bpm = form.Bpm }; UpdateEvent(noteView.ScoreEvents.BpmChangeEvents, item); }); var insertHighSpeedItem = new MenuItem(MainFormStrings.HighSpeed, (s, e) => { var form = new HighSpeedSelectionForm() { SpeedRatio = noteView.ScoreEvents.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 }; UpdateEvent(noteView.ScoreEvents.HighSpeedChangeEvents, item); }); var insertTimeSignatureItem = new MenuItem(MainFormStrings.TimeSignature, (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 }; UpdateEvent(noteView.ScoreEvents.TimeSignatureChangeEvents, item); }); var insertMenuItems = new MenuItem[] { insertBpmItem, insertHighSpeedItem, insertTimeSignatureItem }; var isAbortAtLastNoteItem = new MenuItem(MainFormStrings.AbortAtLastNote, (s, e) => { var item = s as MenuItem; item.Checked = !item.Checked; PreviewManager.IsStopAtLastNote = item.Checked; ApplicationSettings.Default.IsPreviewAbortAtLastNote = item.Checked; }) { Checked = ApplicationSettings.Default.IsPreviewAbortAtLastNote }; var playItem = new MenuItem(MainFormStrings.Play, (s, e) => { if (string.IsNullOrEmpty(CurrentMusicSource?.FilePath)) { MessageBox.Show(this, ErrorStrings.MusicSourceNull, Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } if (!File.Exists(CurrentMusicSource.FilePath)) { MessageBox.Show(this, ErrorStrings.SourceFileNotFound, Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } if (PreviewManager.Playing) { PreviewManager.Stop(); return; } int startTick = noteView.CurrentTick; void lambda(object p, EventArgs q) { isAbortAtLastNoteItem.Enabled = true; PreviewManager.Finished -= lambda; noteView.CurrentTick = startTick; noteView.Editable = CanEdit; } try { CommitChanges(); var context = new SoundPreviewContext(ScoreBook.Score, CurrentMusicSource); if (!PreviewManager.Start(context, startTick)) { return; } isAbortAtLastNoteItem.Enabled = false; PreviewManager.Finished += lambda; noteView.Editable = CanEdit; } catch (Exception ex) { Program.DumpExceptionTo(ex, "sound_exception.json"); } }, (Shortcut)Keys.Space); var stopItem = new MenuItem(MainFormStrings.Stop, (s, e) => { PreviewManager.Stop(); }); var playMenuItems = new MenuItem[] { playItem, stopItem, new MenuItem("-"), isAbortAtLastNoteItem }; var helpMenuItems = new MenuItem[] { new MenuItem(MainFormStrings.Help, (s, e) => System.Diagnostics.Process.Start("https://github.com/paralleltree/Ched/wiki"), Shortcut.F1), new MenuItem(MainFormStrings.VersionInfo, (s, e) => new VersionInfoForm().ShowDialog(this)) }; OperationManager.OperationHistoryChanged += (s, e) => { redoItem.Enabled = OperationManager.CanRedo; undoItem.Enabled = OperationManager.CanUndo; }; return(new MainMenu(new MenuItem[] { new MenuItem(MainFormStrings.FileMenu, fileMenuItems), new MenuItem(MainFormStrings.EditMenu, editMenuItems), new MenuItem(MainFormStrings.ViewMenu, viewMenuItems), new MenuItem(MainFormStrings.InsertMenu, insertMenuItems), // PreviewManager初期化後じゃないといけないのダメ設計でしょ new MenuItem(MainFormStrings.PlayMenu, playMenuItems) { Enabled = PreviewManager.IsSupported }, new MenuItem(MainFormStrings.HelpMenu, helpMenuItems) })); }
private ToolStrip CreateMainToolStrip(NoteView noteView) { var newFileButton = new ToolStripButton(MainFormStrings.NewFile, Resources.NewFileIcon, (s, e) => ClearFile()) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var openFileButton = new ToolStripButton(MainFormStrings.OpenFile, Resources.OpenFileIcon, (s, e) => OpenFile()) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var saveFileButton = new ToolStripButton(MainFormStrings.SaveFile, Resources.SaveFileIcon, (s, e) => SaveFile()) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var exportButton = new ToolStripButton(MainFormStrings.Export, Resources.ExportIcon, (s, e) => { if (LastExportData == null) { ExportFile(); return; } CommitChanges(); try { LastExportData.Exporter.Export(LastExportData.OutputPath, ScoreBook); MessageBox.Show(this, ErrorStrings.ReExportComplete, Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Information); } catch (Exception ex) { MessageBox.Show(this, ErrorStrings.ExportFailed, Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Error); Program.DumpException(ex); } }) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var cutButton = new ToolStripButton(MainFormStrings.Cut, Resources.CutIcon, (s, e) => noteView.CutSelectedNotes()) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var copyButton = new ToolStripButton(MainFormStrings.Copy, Resources.CopyIcon, (s, e) => noteView.CopySelectedNotes()) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var pasteButton = new ToolStripButton(MainFormStrings.Paste, Resources.PasteIcon, (s, e) => noteView.PasteNotes()) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var undoButton = new ToolStripButton(MainFormStrings.Undo, Resources.UndoIcon, (s, e) => noteView.Undo()) { DisplayStyle = ToolStripItemDisplayStyle.Image, Enabled = false }; var redoButton = new ToolStripButton(MainFormStrings.Redo, Resources.RedoIcon, (s, e) => noteView.Redo()) { DisplayStyle = ToolStripItemDisplayStyle.Image, Enabled = false }; var penButton = new ToolStripButton(MainFormStrings.Pen, Resources.EditIcon, (s, e) => noteView.EditMode = EditMode.Edit) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var selectionButton = new ToolStripButton(MainFormStrings.Selection, Resources.SelectionIcon, (s, e) => noteView.EditMode = EditMode.Select) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var eraserButton = new ToolStripButton(MainFormStrings.Eraser, Resources.EraserIcon, (s, e) => noteView.EditMode = EditMode.Erase) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var zoomInButton = new ToolStripButton(MainFormStrings.ZoomIn, Resources.ZoomInIcon) { Enabled = noteView.UnitBeatHeight < 1920, DisplayStyle = ToolStripItemDisplayStyle.Image }; var zoomOutButton = new ToolStripButton(MainFormStrings.ZoomOut, Resources.ZoomOutIcon) { Enabled = noteView.UnitBeatHeight > 30, DisplayStyle = ToolStripItemDisplayStyle.Image }; zoomInButton.Click += (s, e) => { noteView.UnitBeatHeight *= 2; ApplicationSettings.Default.UnitBeatHeight = (int)noteView.UnitBeatHeight; zoomOutButton.Enabled = CanZoomOut; zoomInButton.Enabled = CanZoomIn; UpdateThumbHeight(); }; zoomOutButton.Click += (s, e) => { noteView.UnitBeatHeight /= 2; ApplicationSettings.Default.UnitBeatHeight = (int)noteView.UnitBeatHeight; zoomInButton.Enabled = CanZoomIn; zoomOutButton.Enabled = CanZoomOut; UpdateThumbHeight(); }; ZoomInButton = zoomInButton; ZoomOutButton = zoomOutButton; OperationManager.OperationHistoryChanged += (s, e) => { undoButton.Enabled = noteView.CanUndo; redoButton.Enabled = noteView.CanRedo; }; noteView.EditModeChanged += (s, e) => { selectionButton.Checked = noteView.EditMode == EditMode.Select; penButton.Checked = noteView.EditMode == EditMode.Edit; eraserButton.Checked = noteView.EditMode == EditMode.Erase; }; return(new ToolStrip(new ToolStripItem[] { newFileButton, openFileButton, saveFileButton, exportButton, new ToolStripSeparator(), cutButton, copyButton, pasteButton, new ToolStripSeparator(), undoButton, redoButton, new ToolStripSeparator(), penButton, selectionButton, eraserButton, new ToolStripSeparator(), zoomInButton, zoomOutButton })); }
private MainMenu CreateMainMenu(NoteView noteView) { var importPluginItems = PluginManager.ScoreBookImportPlugins.Select(p => new MenuItem(p.DisplayName, (s, e) => { OpenFile(p.FileFilter, q => { try { using (var reader = new StreamReader(q)) LoadBook(p.Import(reader)); } catch (Exception ex) { MessageBox.Show(this, ErrorStrings.ImportFailed, Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Error); Program.DumpExceptionTo(ex, "import_exception.json"); LoadEmptyBook(); } }); })).ToArray(); var bookPropertiesMenuItem = new MenuItem(MainFormStrings.bookProperty, (s, e) => { var form = new BookPropertiesForm(ScoreBook, CurrentMusicSource); if (form.ShowDialog(this) == DialogResult.OK) { CurrentMusicSource = form.MusicSource; if (string.IsNullOrEmpty(ScoreBook.Path)) { return; } SoundSettings.Default.ScoreSound[ScoreBook.Path] = CurrentMusicSource; SoundSettings.Default.Save(); } }); var fileMenuItems = new MenuItem[] { new MenuItem(MainFormStrings.NewFile + "(&N)", (s, e) => ClearFile()) { Shortcut = Shortcut.CtrlN }, new MenuItem(MainFormStrings.OpenFile + "(&O)", (s, e) => OpenFile()) { Shortcut = Shortcut.CtrlO }, new MenuItem(MainFormStrings.SaveFile + "(&S)", (s, e) => SaveFile()) { Shortcut = Shortcut.CtrlS }, new MenuItem(MainFormStrings.SaveAs + "(&A)", (s, e) => SaveAs()) { Shortcut = Shortcut.CtrlShiftS }, new MenuItem("-"), new MenuItem(MainFormStrings.Import, importPluginItems), new MenuItem(MainFormStrings.Export, (s, e) => ExportFile()), new MenuItem("-"), bookPropertiesMenuItem, new MenuItem("-"), new MenuItem(MainFormStrings.Exit + "(&X)", (s, e) => this.Close()) }; var undoItem = new MenuItem(MainFormStrings.Undo, (s, e) => noteView.Undo()) { Shortcut = Shortcut.CtrlZ, Enabled = false }; var redoItem = new MenuItem(MainFormStrings.Redo, (s, e) => noteView.Redo()) { Shortcut = Shortcut.CtrlY, Enabled = false }; var cutItem = new MenuItem(MainFormStrings.Cut, (s, e) => noteView.CutSelectedNotes(), Shortcut.CtrlX); var copyItem = new MenuItem(MainFormStrings.Copy, (s, e) => noteView.CopySelectedNotes(), Shortcut.CtrlC); var pasteItem = new MenuItem(MainFormStrings.Paste, (s, e) => noteView.PasteNotes(), Shortcut.CtrlV); var pasteFlippedItem = new MenuItem(MainFormStrings.PasteFlipped, (s, e) => noteView.PasteFlippedNotes(), Shortcut.CtrlShiftV); var flipSelectedNotesItem = new MenuItem(MainFormStrings.FlipSelectedNotes, (s, e) => noteView.FlipSelectedNotes()); var removeSelectedNotesItem = new MenuItem(MainFormStrings.RemoveSelectedNotes, (s, e) => noteView.RemoveSelectedNotes(), Shortcut.Del); var removeEventsItem = new MenuItem(MainFormStrings.RemoveEvents, (s, e) => { int minTick = noteView.SelectedRange.StartTick + (noteView.SelectedRange.Duration < 0 ? noteView.SelectedRange.Duration : 0); int maxTick = noteView.SelectedRange.StartTick + (noteView.SelectedRange.Duration < 0 ? 0 : noteView.SelectedRange.Duration); Func <EventBase, bool> isContained = p => p.Tick != 0 && minTick <= p.Tick && maxTick >= p.Tick; var events = ScoreBook.Score.Events; var bpmOp = events.BPMChangeEvents.Where(p => isContained(p)).ToList().Select(p => { ScoreBook.Score.Events.BPMChangeEvents.Remove(p); return(new RemoveEventOperation <BPMChangeEvent>(events.BPMChangeEvents, p)); }).ToList(); var speedOp = events.HighSpeedChangeEvents.Where(p => isContained(p)).ToList().Select(p => { ScoreBook.Score.Events.HighSpeedChangeEvents.Remove(p); return(new RemoveEventOperation <HighSpeedChangeEvent>(events.HighSpeedChangeEvents, p)); }).ToList(); var signatureOp = events.TimeSignatureChangeEvents.Where(p => isContained(p)).ToList().Select(p => { ScoreBook.Score.Events.TimeSignatureChangeEvents.Remove(p); return(new RemoveEventOperation <TimeSignatureChangeEvent>(events.TimeSignatureChangeEvents, p)); }).ToList(); OperationManager.Push(new CompositeOperation("イベント削除", bpmOp.Cast <IOperation>().Concat(speedOp).Concat(signatureOp))); noteView.Invalidate(); }); var insertAirWithAirActionItem = new MenuItem(MainFormStrings.InsertAirWithAirAction, (s, e) => { var item = s as MenuItem; item.Checked = !item.Checked; NoteView.InsertAirWithAirAction = item.Checked; ApplicationSettings.Default.InsertAirWithAirAction = item.Checked; }) { Checked = ApplicationSettings.Default.InsertAirWithAirAction }; var pluginItems = PluginManager.ScorePlugins.Select(p => new MenuItem(p.DisplayName, (s, e) => { CommitChanges(); Action <Score> updateScore = newScore => { var op = new UpdateScoreOperation(ScoreBook.Score, newScore, score => { ScoreBook.Score = score; noteView.UpdateScore(score); }); OperationManager.Push(op); op.Redo(); }; try { p.Run(new ScorePluginArgs(() => ScoreBook.Score.Clone(), noteView.SelectedRange, updateScore)); } catch (Exception ex) { Program.DumpExceptionTo(ex, "plugin_exception.json"); MessageBox.Show(this, ErrorStrings.PluginException, Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Error); } })).ToArray(); var pluginItem = new MenuItem(MainFormStrings.Plugin, pluginItems); var editMenuItems = new MenuItem[] { undoItem, redoItem, new MenuItem("-"), cutItem, copyItem, pasteItem, pasteFlippedItem, new MenuItem("-"), flipSelectedNotesItem, removeSelectedNotesItem, removeEventsItem, new MenuItem("-"), insertAirWithAirActionItem, new MenuItem("-"), pluginItem }; var viewModeItem = new MenuItem(MainFormStrings.ScorePreview, (s, e) => { IsPreviewMode = !IsPreviewMode; ((MenuItem)s).Checked = IsPreviewMode; }, Shortcut.CtrlP); WidenLaneWidthMenuItem = new MenuItem(MainFormStrings.WidenLaneWidth); NarrowLaneWidthMenuItem = new MenuItem(MainFormStrings.NarrowLaneWidth); WidenLaneWidthMenuItem.Click += (s, e) => { noteView.UnitLaneWidth += 4; ApplicationSettings.Default.UnitLaneWidth = noteView.UnitLaneWidth; WidenLaneWidthMenuItem.Enabled = CanWidenLaneWidth; NarrowLaneWidthMenuItem.Enabled = CanNarrowLaneWidth; }; NarrowLaneWidthMenuItem.Click += (s, e) => { noteView.UnitLaneWidth -= 4; ApplicationSettings.Default.UnitLaneWidth = noteView.UnitLaneWidth; WidenLaneWidthMenuItem.Enabled = CanWidenLaneWidth; NarrowLaneWidthMenuItem.Enabled = CanNarrowLaneWidth; }; var viewMenuItems = new MenuItem[] { viewModeItem, new MenuItem("-"), WidenLaneWidthMenuItem, NarrowLaneWidthMenuItem }; var insertBPMItem = new MenuItem("BPM", (s, e) => { var form = new BPMSelectionForm() { BPM = noteView.ScoreEvents.BPMChangeEvents.OrderBy(p => p.Tick).LastOrDefault(p => p.Tick <= noteView.CurrentTick)?.BPM ?? 120m }; if (form.ShowDialog(this) != DialogResult.OK) { return; } var prev = noteView.ScoreEvents.BPMChangeEvents.SingleOrDefault(p => p.Tick == noteView.SelectedRange.StartTick); var item = new BPMChangeEvent() { Tick = noteView.SelectedRange.StartTick, BPM = form.BPM }; var insertOp = new InsertEventOperation <BPMChangeEvent>(noteView.ScoreEvents.BPMChangeEvents, item); if (prev == null) { OperationManager.Push(insertOp); } else { var removeOp = new RemoveEventOperation <BPMChangeEvent>(noteView.ScoreEvents.BPMChangeEvents, prev); noteView.ScoreEvents.BPMChangeEvents.Remove(prev); OperationManager.Push(new CompositeOperation(insertOp.Description, new IOperation[] { removeOp, insertOp })); } noteView.ScoreEvents.BPMChangeEvents.Add(item); noteView.Invalidate(); }); var insertHighSpeedItem = new MenuItem(MainFormStrings.HighSpeed, (s, e) => { var form = new HighSpeedSelectionForm() { SpeedRatio = noteView.ScoreEvents.HighSpeedChangeEvents.OrderBy(p => p.Tick).LastOrDefault(p => p.Tick <= noteView.CurrentTick)?.SpeedRatio ?? 1.0m }; if (form.ShowDialog(this) != DialogResult.OK) { return; } var prev = noteView.ScoreEvents.HighSpeedChangeEvents.SingleOrDefault(p => p.Tick == noteView.SelectedRange.StartTick); var item = new HighSpeedChangeEvent() { Tick = noteView.SelectedRange.StartTick, SpeedRatio = form.SpeedRatio }; var insertOp = new InsertEventOperation <HighSpeedChangeEvent>(noteView.ScoreEvents.HighSpeedChangeEvents, item); if (prev == null) { OperationManager.Push(insertOp); } else { var removeOp = new RemoveEventOperation <HighSpeedChangeEvent>(noteView.ScoreEvents.HighSpeedChangeEvents, prev); noteView.ScoreEvents.HighSpeedChangeEvents.Remove(prev); OperationManager.Push(new CompositeOperation(insertOp.Description, new IOperation[] { removeOp, insertOp })); } noteView.ScoreEvents.HighSpeedChangeEvents.Add(item); noteView.Invalidate(); }); var insertTimeSignatureItem = new MenuItem(MainFormStrings.TimeSignature, (s, e) => { var form = new TimeSignatureSelectionForm(); if (form.ShowDialog(this) != DialogResult.OK) { return; } var prev = noteView.ScoreEvents.TimeSignatureChangeEvents.SingleOrDefault(p => p.Tick == noteView.SelectedRange.StartTick); var item = new TimeSignatureChangeEvent() { Tick = noteView.SelectedRange.StartTick, Numerator = form.Numerator, DenominatorExponent = form.DenominatorExponent }; var insertOp = new InsertEventOperation <TimeSignatureChangeEvent>(noteView.ScoreEvents.TimeSignatureChangeEvents, item); if (prev != null) { noteView.ScoreEvents.TimeSignatureChangeEvents.Remove(prev); var removeOp = new RemoveEventOperation <TimeSignatureChangeEvent>(noteView.ScoreEvents.TimeSignatureChangeEvents, prev); OperationManager.Push(new CompositeOperation(insertOp.Description, new IOperation[] { removeOp, insertOp })); } else { OperationManager.Push(insertOp); } noteView.ScoreEvents.TimeSignatureChangeEvents.Add(item); noteView.Invalidate(); }); var insertMenuItems = new MenuItem[] { insertBPMItem, insertHighSpeedItem, insertTimeSignatureItem }; var isAbortAtLastNoteItem = new MenuItem(MainFormStrings.AbortAtLastNote, (s, e) => { var item = s as MenuItem; item.Checked = !item.Checked; PreviewManager.IsStopAtLastNote = item.Checked; ApplicationSettings.Default.IsPreviewAbortAtLastNote = item.Checked; }) { Checked = ApplicationSettings.Default.IsPreviewAbortAtLastNote }; var playItem = new MenuItem(MainFormStrings.Play, (s, e) => { if (CurrentMusicSource == null) { MessageBox.Show(this, ErrorStrings.MusicSourceNull, Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } if (!File.Exists(CurrentMusicSource.FilePath)) { MessageBox.Show(this, ErrorStrings.SourceFileNotFound, Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } if (PreviewManager.Playing) { PreviewManager.Stop(); return; } int startTick = noteView.CurrentTick; EventHandler lambda = null; lambda = (p, q) => { isAbortAtLastNoteItem.Enabled = true; PreviewManager.Finished -= lambda; noteView.CurrentTick = startTick; }; try { if (!PreviewManager.Start(CurrentMusicSource, startTick)) { return; } isAbortAtLastNoteItem.Enabled = false; PreviewManager.Finished += lambda; noteView.Editable = CanEdit; } catch (Exception ex) { Program.DumpExceptionTo(ex, "sound_exception.json"); } }, (Shortcut)Keys.Space); var stopItem = new MenuItem(MainFormStrings.Stop, (s, e) => { PreviewManager.Stop(); }); var playMenuItems = new MenuItem[] { playItem, stopItem, new MenuItem("-"), isAbortAtLastNoteItem }; var helpMenuItems = new MenuItem[] { new MenuItem(MainFormStrings.Help, (s, e) => System.Diagnostics.Process.Start("https://github.com/paralleltree/Ched/wiki"), Shortcut.F1), new MenuItem(MainFormStrings.VersionInfo, (s, e) => new VersionInfoForm().ShowDialog(this)) }; OperationManager.OperationHistoryChanged += (s, e) => { redoItem.Enabled = noteView.CanRedo; undoItem.Enabled = noteView.CanUndo; }; return(new MainMenu(new MenuItem[] { new MenuItem(MainFormStrings.FileMenu, fileMenuItems), new MenuItem(MainFormStrings.EditMenu, editMenuItems), new MenuItem(MainFormStrings.ViewMenu, viewMenuItems), new MenuItem(MainFormStrings.InsertMenu, insertMenuItems), // PreviewManager初期化後じゃないといけないのダメ設計でしょ new MenuItem(MainFormStrings.PlayMenu, playMenuItems) { Enabled = PreviewManager.IsSupported }, new MenuItem(MainFormStrings.HelpMenu, helpMenuItems) })); }
private ToolStrip CreateMainToolStrip(NoteView noteView) { var newFileButton = new ToolStripButton(MainFormStrings.NewFile, Resources.NewFileIcon, (s, e) => ClearFile()) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var openFileButton = new ToolStripButton(MainFormStrings.OpenFile, Resources.OpenFileIcon, (s, e) => OpenFile()) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var saveFileButton = new ToolStripButton(MainFormStrings.SaveFile, Resources.SaveFileIcon, (s, e) => SaveFile()) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var exportButton = new ToolStripButton(MainFormStrings.Export, Resources.ExportIcon, (s, e) => { if (LastExportData == null) { ExportFile(); return; } HandleExport(LastExportData); }) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var cutButton = new ToolStripButton(MainFormStrings.Cut, Resources.CutIcon, (s, e) => noteView.CutSelectedNotes()) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var copyButton = new ToolStripButton(MainFormStrings.Copy, Resources.CopyIcon, (s, e) => noteView.CopySelectedNotes()) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var pasteButton = new ToolStripButton(MainFormStrings.Paste, Resources.PasteIcon, (s, e) => noteView.PasteNotes()) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var undoButton = new ToolStripButton(MainFormStrings.Undo, Resources.UndoIcon, (s, e) => noteView.Undo()) { DisplayStyle = ToolStripItemDisplayStyle.Image, Enabled = false }; var redoButton = new ToolStripButton(MainFormStrings.Redo, Resources.RedoIcon, (s, e) => noteView.Redo()) { DisplayStyle = ToolStripItemDisplayStyle.Image, Enabled = false }; var penButton = new ToolStripButton(MainFormStrings.Pen, Resources.EditIcon, (s, e) => noteView.EditMode = EditMode.Edit) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var selectionButton = new ToolStripButton(MainFormStrings.Selection, Resources.SelectionIcon, (s, e) => noteView.EditMode = EditMode.Select) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var eraserButton = new ToolStripButton(MainFormStrings.Eraser, Resources.EraserIcon, (s, e) => noteView.EditMode = EditMode.Erase) { DisplayStyle = ToolStripItemDisplayStyle.Image }; var zoomInButton = new ToolStripButton(MainFormStrings.ZoomIn, Resources.ZoomInIcon) { Enabled = noteView.UnitBeatHeight < 1920, DisplayStyle = ToolStripItemDisplayStyle.Image }; var zoomOutButton = new ToolStripButton(MainFormStrings.ZoomOut, Resources.ZoomOutIcon) { Enabled = noteView.UnitBeatHeight > 30, DisplayStyle = ToolStripItemDisplayStyle.Image }; zoomInButton.Click += (s, e) => { noteView.UnitBeatHeight *= 2; ApplicationSettings.Default.UnitBeatHeight = (int)noteView.UnitBeatHeight; zoomOutButton.Enabled = CanZoomOut; zoomInButton.Enabled = CanZoomIn; UpdateThumbHeight(); }; zoomOutButton.Click += (s, e) => { noteView.UnitBeatHeight /= 2; ApplicationSettings.Default.UnitBeatHeight = (int)noteView.UnitBeatHeight; zoomInButton.Enabled = CanZoomIn; zoomOutButton.Enabled = CanZoomOut; UpdateThumbHeight(); }; ZoomInButton = zoomInButton; ZoomOutButton = zoomOutButton; OperationManager.OperationHistoryChanged += (s, e) => { undoButton.Enabled = noteView.CanUndo; redoButton.Enabled = noteView.CanRedo; }; noteView.EditModeChanged += (s, e) => { selectionButton.Checked = noteView.EditMode == EditMode.Select; penButton.Checked = noteView.EditMode == EditMode.Edit; eraserButton.Checked = noteView.EditMode == EditMode.Erase; }; return(new ToolStrip(new ToolStripItem[] { newFileButton, openFileButton, saveFileButton, exportButton, new ToolStripSeparator(), cutButton, copyButton, pasteButton, new ToolStripSeparator(), undoButton, redoButton, new ToolStripSeparator(), penButton, selectionButton, eraserButton, new ToolStripSeparator(), zoomInButton, zoomOutButton })); }
private MainMenu CreateMainMenu(NoteView noteView) { var bookPropertiesMenuItem = new MenuItem("譜面プロパティ", (s, e) => { var form = new BookPropertiesForm(ScoreBook, CurrentMusicSource); if (form.ShowDialog(this) == DialogResult.OK) { CurrentMusicSource = form.MusicSource; if (string.IsNullOrEmpty(ScoreBook.Path)) { return; } SoundConfiguration.Default.ScoreSound[ScoreBook.Path] = CurrentMusicSource; SoundConfiguration.Default.Save(); } }); var fileMenuItems = new MenuItem[] { new MenuItem("新規作成(&N)", (s, e) => ClearFile()) { 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("エクスポート", (s, e) => ExportFile()), new MenuItem("-"), bookPropertiesMenuItem, new MenuItem("-"), new MenuItem("終了(&X)", (s, e) => this.Close()) }; var undoItem = new MenuItem("元に戻す", (s, e) => noteView.Undo()) { Shortcut = Shortcut.CtrlZ, Enabled = false }; var redoItem = new MenuItem("やり直し", (s, e) => noteView.Redo()) { Shortcut = Shortcut.CtrlY, Enabled = false }; var cutItem = new MenuItem("切り取り", (s, e) => noteView.CutSelectedNotes(), Shortcut.CtrlX); var copyItem = new MenuItem("コピー", (s, e) => noteView.CopySelectedNotes(), Shortcut.CtrlC); var pasteItem = new MenuItem("貼り付け", (s, e) => noteView.PasteNotes(), Shortcut.CtrlV); var pasteFlippedItem = new MenuItem("反転貼り付け", (s, e) => noteView.PasteFlippedNotes(), Shortcut.CtrlShiftV); var flipSelectedNotesItem = new MenuItem("選択範囲内ノーツを反転", (s, e) => noteView.FlipSelectedNotes()); var removeSelectedNotesItem = new MenuItem("選択範囲内ノーツを削除", (s, e) => noteView.RemoveSelectedNotes(), Shortcut.Del); var removeEventsItem = new MenuItem("選択範囲内イベントを削除", (s, e) => { int minTick = noteView.SelectedRange.StartTick + (noteView.SelectedRange.Duration < 0 ? noteView.SelectedRange.Duration : 0); int maxTick = noteView.SelectedRange.StartTick + (noteView.SelectedRange.Duration < 0 ? 0 : noteView.SelectedRange.Duration); Func <EventBase, bool> isContained = p => p.Tick != 0 && minTick <= p.Tick && maxTick >= p.Tick; var events = ScoreBook.Score.Events; var bpmOp = events.BPMChangeEvents.Where(p => isContained(p)).ToList().Select(p => { ScoreBook.Score.Events.BPMChangeEvents.Remove(p); return(new RemoveEventOperation <BPMChangeEvent>(events.BPMChangeEvents, p)); }).ToList(); var speedOp = events.HighSpeedChangeEvents.Where(p => isContained(p)).ToList().Select(p => { ScoreBook.Score.Events.HighSpeedChangeEvents.Remove(p); return(new RemoveEventOperation <HighSpeedChangeEvent>(events.HighSpeedChangeEvents, p)); }).ToList(); var signatureOp = events.TimeSignatureChangeEvents.Where(p => isContained(p)).ToList().Select(p => { ScoreBook.Score.Events.TimeSignatureChangeEvents.Remove(p); return(new RemoveEventOperation <TimeSignatureChangeEvent>(events.TimeSignatureChangeEvents, p)); }).ToList(); OperationManager.Push(new CompositeOperation("イベント削除", bpmOp.Cast <IOperation>().Concat(speedOp).Concat(signatureOp))); noteView.Invalidate(); }); var pluginItems = PluginManager.ScorePlugins.Select(p => new MenuItem(p.DisplayName, (s, e) => { CommitChanges(); try { p.Run(ScoreBook.Score); } catch (Exception ex) { Program.DumpExceptionTo(ex, "plugin_exception.json"); MessageBox.Show(this, "プラグインの実行中にエラーが発生しました。", Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Error); } })).ToArray(); var pluginItem = new MenuItem("プラグイン", pluginItems); var editMenuItems = new MenuItem[] { undoItem, redoItem, new MenuItem("-"), cutItem, copyItem, pasteItem, pasteFlippedItem, new MenuItem("-"), flipSelectedNotesItem, removeSelectedNotesItem, removeEventsItem, new MenuItem("-"), pluginItem }; var viewModeItem = new MenuItem("譜面プレビュー", (s, e) => { IsPreviewMode = !IsPreviewMode; ((MenuItem)s).Checked = IsPreviewMode; }, Shortcut.CtrlP); var viewMenuItems = new MenuItem[] { viewModeItem }; var insertBPMItem = new MenuItem("BPM", (s, e) => { var form = new BPMSelectionForm(); if (form.ShowDialog(this) != DialogResult.OK) { return; } var prev = noteView.ScoreEvents.BPMChangeEvents.SingleOrDefault(p => p.Tick == noteView.SelectedRange.StartTick); var item = new Components.Events.BPMChangeEvent() { Tick = noteView.SelectedRange.StartTick, BPM = form.BPM }; var insertOp = new InsertEventOperation <Components.Events.BPMChangeEvent>(noteView.ScoreEvents.BPMChangeEvents, item); if (prev == null) { OperationManager.Push(insertOp); } else { var removeOp = new RemoveEventOperation <Components.Events.BPMChangeEvent>(noteView.ScoreEvents.BPMChangeEvents, prev); noteView.ScoreEvents.BPMChangeEvents.Remove(prev); OperationManager.Push(new CompositeOperation(insertOp.Description, new IOperation[] { removeOp, insertOp })); } noteView.ScoreEvents.BPMChangeEvents.Add(item); noteView.Invalidate(); }); var insertHighSpeedItem = new MenuItem("ハイスピード", (s, e) => { var form = new HighSpeedSelectionForm(); if (form.ShowDialog(this) != DialogResult.OK) { return; } var prev = noteView.ScoreEvents.HighSpeedChangeEvents.SingleOrDefault(p => p.Tick == noteView.SelectedRange.StartTick); var item = new Components.Events.HighSpeedChangeEvent() { Tick = noteView.SelectedRange.StartTick, SpeedRatio = form.SpeedRatio }; var insertOp = new InsertEventOperation <Components.Events.HighSpeedChangeEvent>(noteView.ScoreEvents.HighSpeedChangeEvents, item); if (prev == null) { OperationManager.Push(insertOp); } else { var removeOp = new RemoveEventOperation <Components.Events.HighSpeedChangeEvent>(noteView.ScoreEvents.HighSpeedChangeEvents, prev); noteView.ScoreEvents.HighSpeedChangeEvents.Remove(prev); OperationManager.Push(new CompositeOperation(insertOp.Description, new IOperation[] { removeOp, insertOp })); } noteView.ScoreEvents.HighSpeedChangeEvents.Add(item); noteView.Invalidate(); }); var insertTimeSignatureItem = new MenuItem("拍子", (s, e) => { var form = new TimeSignatureSelectionForm(); if (form.ShowDialog(this) != DialogResult.OK) { return; } var prev = noteView.ScoreEvents.TimeSignatureChangeEvents.SingleOrDefault(p => p.Tick == noteView.SelectedRange.StartTick); var item = new Components.Events.TimeSignatureChangeEvent() { Tick = noteView.SelectedRange.StartTick, Numerator = form.Numerator, DenominatorExponent = form.DenominatorExponent }; var insertOp = new InsertEventOperation <Components.Events.TimeSignatureChangeEvent>(noteView.ScoreEvents.TimeSignatureChangeEvents, item); if (prev != null) { noteView.ScoreEvents.TimeSignatureChangeEvents.Remove(prev); var removeOp = new RemoveEventOperation <Components.Events.TimeSignatureChangeEvent>(noteView.ScoreEvents.TimeSignatureChangeEvents, prev); OperationManager.Push(new CompositeOperation(insertOp.Description, new IOperation[] { removeOp, insertOp })); } else { OperationManager.Push(insertOp); } noteView.ScoreEvents.TimeSignatureChangeEvents.Add(item); noteView.Invalidate(); }); var insertMenuItems = new MenuItem[] { insertBPMItem, insertHighSpeedItem, insertTimeSignatureItem }; var isAbortAtLastNoteItem = new MenuItem("最終ノートで停止", (s, e) => { var item = s as MenuItem; item.Checked = !item.Checked; PreviewManager.IsStopAtLastNote = item.Checked; Settings.Default.IsPreviewAbortAtLastNote = item.Checked; }) { Checked = Settings.Default.IsPreviewAbortAtLastNote }; var playItem = new MenuItem("再生/停止", (s, e) => { if (CurrentMusicSource == null) { MessageBox.Show(this, "譜面プロパティから音源ファイルを指定してください。", Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } if (!File.Exists(CurrentMusicSource.FilePath)) { MessageBox.Show(this, "音源ファイルが見つかりません。", Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } if (PreviewManager.Playing) { PreviewManager.Stop(); return; } int startTick = noteView.CurrentTick; EventHandler lambda = null; lambda = (p, q) => { isAbortAtLastNoteItem.Enabled = true; PreviewManager.Finished -= lambda; noteView.CurrentTick = startTick; }; if (PreviewManager.Start(CurrentMusicSource, startTick)) { isAbortAtLastNoteItem.Enabled = false; PreviewManager.Finished += lambda; noteView.Editable = CanEdit; } }, (Shortcut)Keys.Space); var stopItem = new MenuItem("停止", (s, e) => { PreviewManager.Stop(); }); var playMenuItems = new MenuItem[] { playItem, stopItem, new MenuItem("-"), isAbortAtLastNoteItem }; var helpMenuItems = new MenuItem[] { new MenuItem("ヘルプを開く", (s, e) => System.Diagnostics.Process.Start("https://github.com/paralleltree/Ched/wiki"), Shortcut.F1), new MenuItem("バージョン情報", (s, e) => new VersionInfoForm().ShowDialog(this)) }; OperationManager.OperationHistoryChanged += (s, e) => { redoItem.Enabled = noteView.CanRedo; undoItem.Enabled = noteView.CanUndo; }; return(new MainMenu(new MenuItem[] { new MenuItem("ファイル(&F)", fileMenuItems), new MenuItem("編集(&E)", editMenuItems), new MenuItem("表示(&V)", viewMenuItems), new MenuItem("挿入(&I)", insertMenuItems), // PreviewManager初期化後じゃないといけないのダメ設計でしょ new MenuItem("再生(&P)", playMenuItems) { Enabled = PreviewManager.IsSupported }, new MenuItem("ヘルプ(&H)", helpMenuItems) })); }
public bool Start(SoundSource music, int startTick) { if (Playing) { throw new InvalidOperationException(); } if (music == null) { throw new ArgumentNullException("music"); } SoundManager.Register(ClapSource.FilePath); SoundManager.Register(music.FilePath); EndTick = IsStopAtLastNote ? NoteView.Notes.GetLastTick() : GetTickFromTime(SoundManager.GetDuration(music.FilePath), NoteView.ScoreEvents.BPMChangeEvents); if (EndTick < startTick) { return(false); } var tickSet = new HashSet <int>(); var notes = NoteView.Notes; var shortNotesTick = notes.Taps.Cast <TappableBase>().Concat(notes.ExTaps).Concat(notes.Flicks).Concat(notes.Damages).Select(p => p.Tick); var holdsTick = notes.Holds.SelectMany(p => new int[] { p.StartTick, p.StartTick + p.Duration }); var slidesTick = notes.Slides.SelectMany(p => new int[] { p.StartTick }.Concat(p.StepNotes.Where(q => q.IsVisible).Select(q => q.Tick))); var airActionsTick = notes.AirActions.SelectMany(p => p.ActionNotes.Select(q => p.StartTick + q.Offset)); foreach (int tick in shortNotesTick.Concat(holdsTick).Concat(slidesTick).Concat(airActionsTick)) { tickSet.Add(tick); } TickElement = new LinkedList <int?>(tickSet.Where(p => p >= startTick).OrderBy(p => p).Select(p => new int?(p))).First; BPMElement = new LinkedList <BPMChangeEvent>(NoteView.ScoreEvents.BPMChangeEvents.OrderBy(p => p.Tick)).First; // スタート時まで進める while (TickElement != null && TickElement.Value < startTick) { TickElement = TickElement.Next; } while (BPMElement.Next != null && BPMElement.Next.Value.Tick <= startTick) { BPMElement = BPMElement.Next; } int clapLatencyTick = GetLatencyTick(ClapSource.Latency, (double)BPMElement.Value.BPM); InitialTick = startTick - clapLatencyTick; CurrentTick = InitialTick; StartTick = startTick; TimeSpan startTime = GetTimeFromTick(startTick, NoteView.ScoreEvents.BPMChangeEvents); TimeSpan headGap = TimeSpan.FromSeconds(-music.Latency) - startTime; elapsedTick = 0; Task.Run(() => { LastSystemTick = Environment.TickCount; NoteView.Invoke((MethodInvoker)(() => Timer.Start())); System.Threading.Thread.Sleep(TimeSpan.FromSeconds(Math.Max(ClapSource.Latency, 0))); if (headGap.TotalSeconds > 0) { System.Threading.Thread.Sleep(headGap); } if (!Playing) { return; } SoundManager.Play(music.FilePath, startTime + TimeSpan.FromSeconds(music.Latency)); }) .ContinueWith(p => { if (p.Exception != null) { Program.DumpExceptionTo(p.Exception, "sound_exception.json"); ExceptionThrown?.Invoke(this, EventArgs.Empty); } }); Playing = true; return(true); }
public SoundPreviewManager(NoteView noteView) { ClapSource = new SoundSource("guide.mp3", 0.036); NoteView = noteView; Timer.Tick += Tick; }
public MainForm() { InitializeComponent(); Size = new Size(420, 700); Icon = Resources.MainIcon; ToolStripManager.RenderMode = ToolStripManagerRenderMode.System; OperationManager = new OperationManager(); OperationManager.OperationHistoryChanged += (s, e) => SetText(ScoreBook.Path); OperationManager.ChangesCommited += (s, e) => SetText(ScoreBook.Path); NoteView = new NoteView(OperationManager) { Dock = DockStyle.Fill, UnitBeatHeight = Settings.Default.UnitBeatHeight }; PreviewManager = new SoundPreviewManager(NoteView); PreviewManager.Finished += (s, e) => NoteView.Editable = CanEdit; PreviewManager.TickUpdated += (s, e) => NoteView.CurrentTick = e.Tick; NoteViewScrollBar = new VScrollBar() { Dock = DockStyle.Right, Minimum = -NoteView.UnitBeatTick * 4 * 20, SmallChange = NoteView.UnitBeatTick }; Action <ScrollBar> processScrollBarRangeExtension = s => { if (NoteViewScrollBar.Value < NoteViewScrollBar.Minimum * 0.9f) { NoteViewScrollBar.Minimum = (int)(NoteViewScrollBar.Minimum * 1.2); } }; 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()); processScrollBarRangeExtension(NoteViewScrollBar); }; NoteView.DragScroll += (s, e) => { NoteViewScrollBar.Value = Math.Max(-NoteView.HeadTick, NoteViewScrollBar.Minimum); processScrollBarRangeExtension(NoteViewScrollBar); }; NoteViewScrollBar.ValueChanged += (s, e) => { NoteView.HeadTick = -NoteViewScrollBar.Value / 60 * 60; // 60の倍数できれいに表示されるので… NoteView.Invalidate(); }; NoteViewScrollBar.Scroll += (s, e) => { if (e.Type == ScrollEventType.EndScroll) { processScrollBarRangeExtension(NoteViewScrollBar); } }; AllowDrop = true; DragEnter += (s, e) => { e.Effect = DragDropEffects.None; if (e.Data.GetDataPresent(DataFormats.FileDrop)) { var items = (string[])e.Data.GetData(DataFormats.FileDrop); if (items.Length == 1 && items.All(p => Path.GetExtension(p) == FileExtension && File.Exists(p))) { e.Effect = DragDropEffects.Copy; } } }; DragDrop += (s, e) => { string path = ((string[])e.Data.GetData(DataFormats.FileDrop)).Single(); if (OperationManager.IsChanged && !this.ConfirmDiscardChanges()) { return; } LoadFile(path); }; FormClosing += (s, e) => { if (OperationManager.IsChanged && !this.ConfirmDiscardChanges()) { e.Cancel = true; return; } Settings.Default.Save(); }; using (var manager = this.WorkWithLayout()) { this.Menu = CreateMainMenu(NoteView); this.Controls.Add(NoteView); this.Controls.Add(NoteViewScrollBar); this.Controls.Add(CreateNewNoteTypeToolStrip(NoteView)); this.Controls.Add(CreateMainToolStrip(NoteView)); } NoteView.NewNoteType = NoteType.Tap; NoteView.EditMode = EditMode.Edit; LoadBook(new ScoreBook()); SetText(); if (!PreviewManager.IsSupported) { MessageBox.Show(this, "簡易プレビューが利用できない環境です。", Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Information); } }