private static void SetEventToSetCursor(MadcaDisplay display, NoteBook noteBook, IReadOnlyEditorStatus status) { var box = display.PictureBox; var env = display.EditorLaneEnvironment; box.MouseMove += (s, e) => { if (status.EditorMode != EditorMode.Edit) { box.Cursor = Cursors.Default; return; } if (!GetSelectedNote(e.Location, display, noteBook, out var note)) { box.Cursor = Cursors.Default; return; } var area = note.SelectedNoteArea(e.Location, env); if (area == SelectedNoteArea.Left || area == SelectedNoteArea.Right) { box.Cursor = Cursors.SizeWE; return; } if (area == SelectedNoteArea.Center) { box.Cursor = Cursors.SizeAll; return; } box.Cursor = Cursors.Default; }; }
private static void SetEventToPutNote( MadcaDisplay display, NoteBook noteBook, IReadOnlyList <IReadOnlyScore> scores, OperationManager opManager, IReadOnlyEditorStatus status) { var box = display.PictureBox; var laneEnv = display.EditorLaneEnvironment; box.MouseDown += (s, e) => { if (status.EditorMode != EditorMode.Add || status.NoteMode == NoteMode.Hold || status.NoteMode == NoteMode.Field) { return; } var area = laneEnv.GetEditorLaneRegion(e.Location); if (area == EditorLaneRegion.Lane && e.Button == MouseButtons.Left) { var res = PositionConverter.ConvertRealToVirtual(laneEnv, e.Location, status.BeatStride, scores, out Position position); if (!res) { return; } var note = MyUtil.NoteFactory(position.Lane, position.Timing, new NoteSize(status.NoteSize), status.NoteMode); if (note is null) { return; } // HACK: この辺の処理どうしようかな opManager.AddAndInvokeOperation(new AddShortNoteOperation(noteBook, note)); } }; }
private static void SetEventToPutHold( MadcaDisplay display, NoteBook noteBook, IReadOnlyList <IReadOnlyScore> scores, OperationManager opManager, IReadOnlyEditorStatus status) { var box = display.PictureBox; var env = display.EditorLaneEnvironment; var holder = display.KeyTokenHolder; var key = new KeyToken(); HoldEnd end = null; box.MouseDown += (s, e) => { if (holder.Locked) { return; } if (status.EditorMode != EditorMode.Add || status.NoteMode != NoteMode.Hold) { return; } var area = env.GetEditorLaneRegion(e.Location); if (area == EditorLaneRegion.Lane && e.Button == MouseButtons.Left) { var res = PositionConverter.ConvertRealToVirtual(env, e.Location, status.BeatStride, scores, out Position position); if (!res) { return; } var hold = new Hold(position.Lane, position.Timing, position.Timing + status.BeatStride, new NoteSize(status.NoteSize)); end = hold.HoldEnd; opManager.AddAndInvokeOperation(new AddHoldOperation(noteBook, hold)); holder.Lock(key); } }; box.MouseMove += (s, e) => { if (!holder.CanUnLock(key)) { return; } var res = PositionConverter.ConvertRealToVirtual(env, e.Location, status.BeatStride, scores, out Position position); if (!res) { return; } end.ReLocate(position.Lane, position.Timing); }; box.MouseUp += (s, e) => { if (!holder.UnLock(key)) { return; } end = null; }; }
/// <summary> /// Refreshはここで一元管理する(ここ以外では呼び出さない)ことにする /// </summary> /// <param name="box">描画先のPictureBox</param> private static void SetEventForRefreshRule(MadcaDisplay display) { var box = display.PictureBox; box.MouseDown += (s, e) => box.Refresh(); box.MouseMove += (s, e) => box.Refresh(); box.SizeChanged += (s, e) => box.Refresh(); box.MouseWheel += (s, e) => box.Refresh(); }
private static void SetEventToDrawPreviewNote( MadcaDisplay display, IReadOnlyList <IReadOnlyScore> scores, IReadOnlyEditorStatus status) { var box = display.PictureBox; var laneEnv = display.EditorLaneEnvironment; var previewEnv = display.PreviewDisplayEnvironment; var holder = display.KeyTokenHolder; var note = new PreviewNote(new LanePotision(0), new TimingPosition(1, 0), new NoteSize(status.NoteSize)); bool visible = false; box.MouseMove += (s, e) => { if (holder.Locked || status.EditorMode != EditorMode.Add) { visible = false; return; } var area = laneEnv.GetEditorLaneRegion(e.Location); if (area == EditorLaneRegion.Lane) { visible = true; var res = PositionConverter.ConvertRealToVirtual(laneEnv, e.Location, status.BeatStride, scores, out Position position); if (res) { note.ReLocate(position.Lane, position.Timing); } } else { visible = false; } }; box.Paint += (s, e) => { if (visible) { note.ReSize(new NoteSize(status.NoteSize)); note.SelectedNote = status.NoteMode.ToNoteType(); NoteDrawer.DrawToLane(e.Graphics, laneEnv, note); NoteDrawer.DrawToPreview(e.Graphics, previewEnv, note); } }; }
private static bool GetSelectedNote(Point p, MadcaDisplay display, NoteBook noteBook, out NoteBase note) { var env = display.EditorLaneEnvironment; note = noteBook.Notes.FindLast(x => x.GetRectangle(env).ContainsEx(p, env)); if (note == null) { foreach (var hold in noteBook.Holds.Reverse()) { note = hold.AllNotes.Find(x => x.GetRectangle(env).ContainsEx(p, env)); if (note != null) { break; } } if (note == null) { return(false); } } return(true); }
private static void SetEventToDeleteNote(MadcaDisplay display, NoteBook noteBook, OperationManager opManager, IReadOnlyEditorStatus status) { display.PictureBox.MouseDown += (s, e) => { var env = display.EditorLaneEnvironment; if (status.EditorMode != EditorMode.Delete) { return; } var area = env.GetEditorLaneRegion(e.Location); if (area == EditorLaneRegion.Lane && e.Button == MouseButtons.Left) { var note = noteBook.Notes.FindLast(x => x.GetRectangle(env).ContainsEx(e.Location, env)); if (note != null) { opManager.AddAndInvokeOperation(new DeleteShortNoteOperation(noteBook, note)); return; } foreach (var hold in noteBook.Holds.Reverse()) { if (hold.HoldBegin.GetRectangle(env).ContainsEx(e.Location, env)) { opManager.AddAndInvokeOperation(new DeleteHoldOperation(noteBook, hold)); return; } foreach (var step in hold.StepNotes) { if (step.GetRectangle(env).ContainsEx(e.Location, env)) { opManager.AddAndInvokeOperation(new DeleteHoldStepOperation(hold, step)); return; } } } } }; }
private static void SetEventToReSizeNote( MadcaDisplay display, NoteBook noteBook, IReadOnlyList <IReadOnlyScore> scores, OperationManager opManager, IReadOnlyEditorStatus status) { var box = display.PictureBox; var env = display.EditorLaneEnvironment; var holder = display.KeyTokenHolder; var key = new KeyToken(); NoteBase note = null; Position prevPos = null; NoteSize prevSize = null; Position mouseBegin = null; SelectedNoteArea noteArea = SelectedNoteArea.None; box.MouseDown += (s, e) => { if (holder.Locked || status.EditorMode != EditorMode.Edit) { return; } var area = env.GetEditorLaneRegion(e.Location); if (area == EditorLaneRegion.Lane && e.Button == MouseButtons.Left) { if (!GetSelectedNote(e.Location, display, noteBook, out note)) { return; } noteArea = note.SelectedNoteArea(e.Location, env); if (!(noteArea == SelectedNoteArea.Left || noteArea == SelectedNoteArea.Right)) { return; } prevPos = new Position(note.Lane, note.Timing); prevSize = new NoteSize(note.NoteSize); var res = PositionConverter.ConvertRealToVirtual(env, e.Location, status.BeatStride, scores, out mouseBegin); if (!res) { return; } holder.Lock(key); } }; box.MouseMove += (s, e) => { if (!holder.CanUnLock(key)) { return; } var res = PositionConverter.ConvertRealToVirtual(env, e.Location, status.BeatStride, scores, out Position position); if (!res) { return; } var lane = position.Lane.RawLane - mouseBegin.Lane.RawLane; switch (noteArea) { case SelectedNoteArea.Left: { var diff = prevSize.Size - lane; if (1 <= diff && diff <= MadcaEnv.LaneCount) { note.ReLocate(new LanePotision(prevPos.Lane.RawLane + lane), note.Timing); } note.ReSize(new NoteSize(prevSize.Size - lane)); return; } case SelectedNoteArea.Right: { note.ReSize(new NoteSize(prevSize.Size + lane)); return; } default: return; } }; box.MouseUp += (s, e) => { if (!holder.UnLock(key)) { return; } var ops = new List <Operation>(); // TODO: 条件式要検討 if (prevPos.Lane.RawLane != note.Lane.RawLane || prevPos.Timing != note.Timing) { ops.Add(new ReLocateNoteOperation(note, prevPos, new Position(note.Lane, note.Timing))); } if (prevSize != note.NoteSize) { ops.Add(new ReSizeNoteOperation(note, prevSize, note.NoteSize)); } if (ops.Any()) { opManager.AddOperation(new CompositeOperation(ops.ToArray())); } note = null; }; }
private static void SetEventToReLocateNote( MadcaDisplay display, NoteBook noteBook, IReadOnlyList <IReadOnlyScore> scores, OperationManager opManager, IReadOnlyEditorStatus status) { var box = display.PictureBox; var env = display.EditorLaneEnvironment; var holder = display.KeyTokenHolder; var key = new KeyToken(); NoteBase note = null; Position prev = null; Position mouseBegin = null; box.MouseDown += (s, e) => { if (holder.Locked || status.EditorMode != EditorMode.Edit) { return; } var area = env.GetEditorLaneRegion(e.Location); if (area == EditorLaneRegion.Lane && e.Button == MouseButtons.Left) { if (!GetSelectedNote(e.Location, display, noteBook, out note)) { return; } if (note.SelectedNoteArea(e.Location, env) != SelectedNoteArea.Center) { return; } prev = new Position(note.Lane, note.Timing); var res = PositionConverter.ConvertRealToVirtual(env, e.Location, status.BeatStride, scores, out mouseBegin); if (!res) { return; } holder.Lock(key); } }; box.MouseMove += (s, e) => { if (!holder.CanUnLock(key)) { return; } var res = PositionConverter.ConvertRealToVirtual(env, e.Location, status.BeatStride, scores, out Position position); if (!res) { return; } var lane = position.Lane.RawLane - mouseBegin.Lane.RawLane; var timing = position.Timing - mouseBegin.Timing; note.ReLocate(new LanePotision(prev.Lane.RawLane + lane), prev.Timing + timing); }; box.MouseUp += (s, e) => { if (!holder.UnLock(key)) { return; } // TODO: 条件式要検討 if (prev.Lane.RawLane != note.Lane.RawLane || prev.Timing != note.Timing) { opManager.AddOperation(new ReLocateNoteOperation(note, prev, new Position(note.Lane, note.Timing))); } note = null; }; }
public MainForm() { InitializeComponent(); Text = appName; var display = new MadcaDisplay(new PictureBox() { Location = new Point(), Size = ClientSize }); var fumen = new MadcaFumenData(); var scoreBook = fumen.ScoreBook; var noteBook = fumen.NoteBook; var operationManager = new OperationManager(); var status = new EditorStatus(EditorMode.Add, NoteMode.Touch, 8, new TimingPosition(8, 1)); for (var i = 0; i < 100; ++i) { scoreBook.AddScoreLast(new Score(4, 4)); } // スクロールバーのための初期設定(ちょっと雑実装?) display.VScrollBar.Maximum = (int)(scoreBook.Size.BarRatio * display.EditorLaneEnvironment.TimingUnitHeight); display.VScrollBar.Value = display.VScrollBar.Maximum; SetEditorMode(EditorMode.Add, status); tsbAdd.Click += (s, e) => SetEditorMode(EditorMode.Add, status); tsbEdit.Click += (s, e) => SetEditorMode(EditorMode.Edit, status); tsbDelete.Click += (s, e) => SetEditorMode(EditorMode.Delete, status); tsbUndo.Enabled = tsbRedo.Enabled = false; tsbUndo.Checked = tsbRedo.Checked = false; tsbUndo.Click += (s, e) => { operationManager.Undo(); display.PictureBox.Refresh(); }; tsbRedo.Click += (s, e) => { operationManager.Redo(); display.PictureBox.Refresh(); }; operationManager.UndoStatusChanged += (b) => tsbUndo.Enabled = b; operationManager.RedoStatusChanged += (b) => tsbRedo.Enabled = b; SetNoteMode(NoteMode.Touch, status); tsbTouch.Click += (s, e) => SetNoteMode(NoteMode.Touch, status); tsbChain.Click += (s, e) => SetNoteMode(NoteMode.Chain, status); tsbSlideL.Click += (s, e) => SetNoteMode(NoteMode.SlideL, status); tsbSlideR.Click += (s, e) => SetNoteMode(NoteMode.SlideR, status); tsbSnapU.Click += (s, e) => SetNoteMode(NoteMode.SnapU, status); tsbSnapD.Click += (s, e) => SetNoteMode(NoteMode.SnapD, status); tsbHold.Click += (s, e) => SetNoteMode(NoteMode.Hold, status); tsbHoldStep.Click += (s, e) => SetNoteMode(NoteMode.HoldRelay, status); tsbField.Click += (s, e) => SetNoteMode(NoteMode.Field, status); #region ToolStripMenuItemの設定 tsmiOpen.Click += (s, e) => { using (var dialog = new OpenFileDialog() { Filter = "MADCA譜面ファイル(*.mdc)|*.mdc", Title = "開く" }) { var result = dialog.ShowDialog(); if (result == DialogResult.OK) { string jsonString = default; try { jsonString = File.ReadAllText(dialog.FileName); } catch (Exception) { MessageBox.Show( "譜面ファイルの読み取りに失敗しました。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } try { var fumenInput = JsonSerializer.Deserialize <JsonObject>(jsonString, new JsonSerializerOptions()); if (fumenInput == null) { MessageBox.Show( "譜面データのデシリアライズに失敗しました。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error); } else { try { MyUtil.Normalize(fumenInput); fumen.Exchange(fumenInput); } catch (Exception) { MessageBox.Show( "譜面データの読み込みに失敗しました。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } catch (Exception) { MessageBox.Show( "譜面データのデシリアライズに失敗しました。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } }; tsmiSaveAs.Click += (s, e) => { using (var dialog = new SaveFileDialog() { FileName = "NewScore.mdc", Filter = "MADCA譜面ファイル(*.mdc)|*.mdc", Title = "名前を付けて保存" }) { var result = dialog.ShowDialog(); if (result == DialogResult.OK) { string jsonString = default; try { jsonString = JsonSerializer.Serialize(fumen.Exchange(), new JsonSerializerOptions { WriteIndented = true }); try { File.WriteAllText(dialog.FileName, jsonString); } catch (Exception) { MessageBox.Show( "譜面データの書き込みに失敗しました。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error); } } catch (Exception) { MessageBox.Show("譜面データのシリアライズに失敗しました。"); } } } }; #endregion #region 分数指定用ComboBoxの設定 var beatStride = new List <uint>() { 4, 8, 12, 16, 24, 32, 48, 64 }; tscbBeat.Items.AddRange(beatStride.Select(x => $"1 / {x}").ToArray()); tscbBeat.Items.Add("カスタム..."); tscbBeat.SelectedIndexChanged += (s, e) => { if (tscbBeat.SelectedIndex == tscbBeat.Items.Count - 1) { using (var dialog = new BeatStrideDialog()) { dialog.BeatStrideConfirmed += (_, t) => { status.BeatStride = t; // 反映されない...(すでに存在するものの場合は反映された) tscbBeat.Text = $"{t.CntValue} / {t.DivValue}"; }; dialog.ShowDialog(); } return; } if (tscbBeat.SelectedIndex < 0 || tscbBeat.SelectedIndex >= beatStride.Count) { return; } status.BeatStride = new TimingPosition(beatStride[tscbBeat.SelectedIndex], 1); }; tscbBeat.SelectedIndex = 0; #endregion #region ノーツサイズ設定用UI関連 var noteSizeUpDown = new NumericUpDown() { Font = new Font("Yu Gothic UI", 9), Minimum = 1, Maximum = MadcaEnv.LaneCount }; noteSizeUpDown.ValueChanged += (s, e) => { status.NoteSize = (int)noteSizeUpDown.Value; tscbFavoriteNoteSize.SelectedIndex = -1; display.PictureBox.Refresh(); }; var idx = toolStrip1.Items.IndexOf(tsbAddFavoriteSize); toolStrip1.Items.Insert(idx, new ToolStripControlHost(noteSizeUpDown)); var favoriteSize = new List <int>(); tsbAddFavoriteSize.Click += (s, e) => { var size = (int)noteSizeUpDown.Value; if (!favoriteSize.Contains(size)) { favoriteSize.Add(size); tscbFavoriteNoteSize.Items.Clear(); tscbFavoriteNoteSize.Items.AddRange(favoriteSize.OrderBy(n => n).Select(x => x.ToString()).ToArray()); } tscbFavoriteNoteSize.SelectedItem = size.ToString(); }; tscbFavoriteNoteSize.SelectedIndexChanged += (s, e) => { if (tscbFavoriteNoteSize.SelectedIndex == -1) { return; } var selectedIndex = tscbFavoriteNoteSize.SelectedIndex; var item = tscbFavoriteNoteSize.SelectedItem.ToString(); noteSizeUpDown.Value = int.Parse(item); tscbFavoriteNoteSize.SelectedIndex = selectedIndex; }; tsbDeleteFavoriteSize.Click += (s, e) => { if (tscbFavoriteNoteSize.SelectedIndex == -1) { return; } var item = tscbFavoriteNoteSize.SelectedItem.ToString(); favoriteSize.Remove(int.Parse(item)); var selectedIndex = tscbFavoriteNoteSize.SelectedIndex; tscbFavoriteNoteSize.Items.RemoveAt(tscbFavoriteNoteSize.SelectedIndex); tscbFavoriteNoteSize.SelectedIndex = selectedIndex < tscbFavoriteNoteSize.Items.Count ? selectedIndex : tscbFavoriteNoteSize.Items.Count - 1; }; noteSizeUpDown.Value = status.NoteSize; #endregion #if DEBUG var time = new Stopwatch(); display.PictureBox.Paint += (s, e) => time.Restart(); #endif display.PictureBox.Paint += (s, e) => { e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; // まずレーンを描画 LaneDrawer.Draw(e.Graphics, display.EditorLaneEnvironment, scoreBook.Scores); PreviewDrawer.Draw(e.Graphics, display.PreviewDisplayEnvironment, scoreBook.Scores); // 次にレーン上にノーツを描画 NoteDrawer.DrawToLane(e.Graphics, display.EditorLaneEnvironment, noteBook); NoteDrawer.DrawToPreview(e.Graphics, display.PreviewDisplayEnvironment, noteBook); }; SizeChanged += (s, e) => { display.PictureBox.Size = ClientSize; }; Controls.Add(display.PictureBox); MinimumSize = new Size((int)display.EditorLaneEnvironment.SideMargin * 2, 10); SetEventToSetCursor(display, noteBook, status); SetEventToPutNote(display, noteBook, scoreBook.Scores, operationManager, status); SetEventToPutHold(display, noteBook, scoreBook.Scores, operationManager, status); SetEventToPutHoldRelay(display, noteBook, scoreBook.Scores, operationManager, status); SetEventToReLocateNote(display, noteBook, scoreBook.Scores, operationManager, status); SetEventToReSizeNote(display, noteBook, scoreBook.Scores, operationManager, status); SetEventToDeleteNote(display, noteBook, operationManager, status); SetEventToDrawPreviewNote(display, scoreBook.Scores, status); SetEventForRefreshRule(display); // 各種SetEvent関数の最後に置く #if DEBUG display.PictureBox.Paint += (s, e) => { time.Stop(); Console.WriteLine($"Time[ms]: {time.ElapsedMilliseconds}"); }; #endif }