예제 #1
0
        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;
            };
        }
예제 #2
0
        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));
                }
            };
        }
예제 #3
0
        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;
            };
        }
예제 #4
0
        /// <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();
        }
예제 #5
0
        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);
                }
            };
        }
예제 #6
0
        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);
        }
예제 #7
0
        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;
                            }
                        }
                    }
                }
            };
        }
예제 #8
0
        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;
            };
        }
예제 #9
0
        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;
            };
        }
예제 #10
0
        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
        }