diff --git a/BAKKA-Editor/CircleView.cs b/BAKKA-Editor/CircleView.cs index 22c8e7b..f298592 100644 --- a/BAKKA-Editor/CircleView.cs +++ b/BAKKA-Editor/CircleView.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Drawing.Drawing2D; using System.Threading.Tasks; namespace BAKKA_Editor @@ -33,6 +34,17 @@ namespace BAKKA_Editor private int SelectTransparency = 110; private int FlairTransparency = 75; + // Graphics. + BufferedGraphicsContext gfxContext = BufferedGraphicsManager.Current; + BufferedGraphics bufGraphics; + + // Mouse information. Public so other GUI elements can be updated with their values. + public int mouseDownPos = -1; + public Point mouseDownPt; + public int lastMousePos = -1; + public bool rolloverPos = false; + public bool rolloverNeg = false; + public CircleView(SizeF size) { Update(size); @@ -61,7 +73,7 @@ namespace BAKKA_Editor FlairPen = new Pen(Color.FromArgb(FlairTransparency, Color.Yellow), PanelSize.Width * 8.0f / 600.0f); } - public ArcInfo GetScaledRect(float objectTime) + private ArcInfo GetScaledRect(float objectTime) { ArcInfo info = new(); float notescaleInit = 1 - ((objectTime - CurrentMeasure) * (1 / TotalMeasureShowNotes)); // Scale from 0-1 @@ -76,7 +88,7 @@ namespace BAKKA_Editor return info; } - public ArcInfo GetArcInfo(Note note) + private ArcInfo GetArcInfo(Note note) { ArcInfo info = GetScaledRect(note.Measure); info.StartAngle = -note.Position * 6; @@ -89,6 +101,339 @@ namespace BAKKA_Editor return info; } + // Updates the mouse down position within the circle, and returns the new position. + public void UpdateMouseDown(float xCen, float yCen, Point mousePt) + { + float theta = (float)(Math.Atan2(yCen, xCen) * 180.0f / Math.PI); + if (theta < 0) + theta += 360.0f; + // Left click moves the cursor + mouseDownPos = (int)(theta / 6.0f); + mouseDownPt = mousePt; + lastMousePos = -1; + rolloverPos = false; + rolloverNeg = false; + } + + public void UpdateMouseUp() + { + if (mouseDownPos <= -1) + { + return; + } + + // Reset position and point. + mouseDownPos = -1; + mouseDownPt = new Point(); + } + + // Updates the mouse position and returns the new position in degrees. + public int UpdateMouseMove(float xCen, float yCen) + { + float thetaCalc = (float)(Math.Atan2(yCen, xCen) * 180.0f / Math.PI); + if (thetaCalc < 0) + thetaCalc += 360.0f; + int theta = (int)(thetaCalc / 6.0f); + + int delta = theta - lastMousePos; + // Handle rollover + if (delta == -59) + { + if (rolloverNeg) + rolloverNeg = false; + else + rolloverPos = true; + } + else if (delta == 59) + { + if (rolloverPos) + rolloverPos = false; + else + rolloverNeg = true; + } + lastMousePos = theta; + + return theta; + } + + public void DrawBackground(int width, int height, Color color) + { + Rectangle panelRect = new Rectangle(0, 0, width, height); + + // Set drawing mode + bufGraphics.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed; + // Draw background + bufGraphics.Graphics.FillRectangle(new SolidBrush(color), panelRect); + } + + public void DrawMasks(Chart chart) + { + var masks = chart.Notes.Where( + x => x.Measure <= CurrentMeasure + && x.IsMask).ToList(); + foreach (var mask in masks) + { + if (mask.NoteType == NoteType.MaskAdd) + { + // Check if there's a MaskRemove that counters the MaskAdd (unless the MaskAdd is later) + var rem = masks.FirstOrDefault(x => x.NoteType == NoteType.MaskRemove && + x.Position == mask.Position && x.Size == mask.Size); + if (rem == null || rem.Measure < mask.Measure) + bufGraphics.Graphics.FillPie(MaskBrush, DrawRect.ToInt(), -mask.Position * 6.0f, -mask.Size * 6.0f); + } + } + } + + public void DrawCircle() + { + // Switch drawing modes + bufGraphics.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; + + // Draw measure circle + for (float meas = (float)Math.Ceiling(CurrentMeasure); (meas - CurrentMeasure) < TotalMeasureShowNotes; meas += 1.0f) + { + var info = GetScaledRect(meas); + if (info.Rect.Width >= 1) + { + bufGraphics.Graphics.DrawEllipse(BeatPen, info.Rect); + } + } + + // Draw base circle + bufGraphics.Graphics.DrawEllipse(TickMediumPen, DrawRect); + } + + public void DrawDegreeLines() + { + for (int i = 0; i < 360; i += 6) + { + PointF startPoint = new PointF( + (float)(Radius * Math.Cos(Utils.DegToRad(i))) + CenterPoint.X, + (float)(Radius * Math.Sin(Utils.DegToRad(i))) + CenterPoint.Y); + float tickLength = PanelSize.Width * 10.0f / 285.0f; + float innerRad = Radius - tickLength; + Pen activePen; + if (i % 90 == 0) + { + innerRad = Radius - (tickLength * 3.5f); + activePen = TickMajorPen; + } + else if (i % 30 == 0) + { + innerRad = Radius - (tickLength * 2.5f); + activePen = TickMediumPen; + } + else + { + activePen = TickMinorPen; + } + PointF endPoint = new PointF( + (float)(innerRad * Math.Cos(Utils.DegToRad(i))) + CenterPoint.X, + (float)(innerRad * Math.Sin(Utils.DegToRad(i))) + CenterPoint.Y); + + bufGraphics.Graphics.DrawLine(activePen, startPoint, endPoint); + } + } + + public void DrawHolds(Chart chart, bool highlightSelectedNote, int selectedNoteIndex) + { + ArcInfo currentInfo = GetScaledRect(CurrentMeasure); + ArcInfo endInfo = GetScaledRect(CurrentMeasure + TotalMeasureShowNotes); + + // First, draw holes that start before the viewpoint and have nodes that end after + List holdNotes = chart.Notes.Where( + x => x.Measure < CurrentMeasure + && x.NextNote != null + && x.NextNote.Measure > (CurrentMeasure + TotalMeasureShowNotes) + && x.IsHold).ToList(); + foreach (var note in holdNotes) + { + ArcInfo info = GetArcInfo(note); + ArcInfo nextInfo = GetArcInfo((Note)note.NextNote); + //GraphicsPath path = new GraphicsPath(); + //path.AddArc(endInfo.Rect, info.StartAngle, info.ArcLength); + //path.AddArc(currentInfo.Rect, info.StartAngle + info.ArcLength, -info.ArcLength); + //bufGraphics.Graphics.FillPath(HoldBrush, path); + + float ratio = (currentInfo.Rect.Width - nextInfo.Rect.Width) / (info.Rect.Width - nextInfo.Rect.Width); + float startNoteAngle = nextInfo.StartAngle; + float endNoteAngle = info.StartAngle; + if (nextInfo.StartAngle > info.StartAngle && (Math.Abs(nextInfo.StartAngle - info.StartAngle) > 180)) + { + startNoteAngle -= 360; + } + else if (info.StartAngle > nextInfo.StartAngle && (Math.Abs(nextInfo.StartAngle - info.StartAngle) > 180)) + { + endNoteAngle -= 360; + } + float startAngle = ratio * (endNoteAngle - startNoteAngle) + startNoteAngle; + float endAngle = ratio * ((endNoteAngle - info.ArcLength) - (startNoteAngle - nextInfo.ArcLength)) + + (startNoteAngle - nextInfo.ArcLength); + float arcLength = startAngle - endAngle; + + float ratio2 = (endInfo.Rect.Width - nextInfo.Rect.Width) / (info.Rect.Width - nextInfo.Rect.Width); + float startNoteAngle2 = nextInfo.StartAngle; + float endNoteAngle2 = info.StartAngle; + if (nextInfo.StartAngle > info.StartAngle && (Math.Abs(nextInfo.StartAngle - info.StartAngle) > 180)) + { + startNoteAngle2 -= 360; + } + else if (info.StartAngle > nextInfo.StartAngle && (Math.Abs(nextInfo.StartAngle - info.StartAngle) > 180)) + { + endNoteAngle2 -= 360; + } + float startAngle2 = ratio2 * (endNoteAngle2 - startNoteAngle2) + startNoteAngle2; + float endAngle2 = ratio2 * ((endNoteAngle2 - info.ArcLength) - (startNoteAngle2 - nextInfo.ArcLength)) + + (startNoteAngle2 - nextInfo.ArcLength); + float arcLength2 = startAngle2 - endAngle2; + + GraphicsPath path = new GraphicsPath(); + path.AddArc(currentInfo.Rect, startAngle, arcLength); + path.AddArc(endInfo.Rect, startAngle2 + arcLength2, -arcLength2); + bufGraphics.Graphics.FillPath(HoldBrush, path); + } + + // Second, draw all the notes on-screen + holdNotes = chart.Notes.Where( + x => x.Measure >= CurrentMeasure + && x.Measure <= (CurrentMeasure + TotalMeasureShowNotes) + && x.IsHold).ToList(); + foreach (var note in holdNotes) + { + ArcInfo info = GetArcInfo(note); + + // If the previous note is off-screen, this case handles that + if (note.PrevNote != null && note.PrevNote.Measure < CurrentMeasure) + { + ArcInfo prevInfo = GetArcInfo((Note)note.PrevNote); + float ratio = (currentInfo.Rect.Width - info.Rect.Width) / (prevInfo.Rect.Width - info.Rect.Width); + float startNoteAngle = info.StartAngle; + float endNoteAngle = prevInfo.StartAngle; + if (info.StartAngle > prevInfo.StartAngle && (Math.Abs(info.StartAngle - prevInfo.StartAngle) > 180)) + { + startNoteAngle -= 360; + } + else if (prevInfo.StartAngle > info.StartAngle && (Math.Abs(info.StartAngle - prevInfo.StartAngle) > 180)) + { + endNoteAngle -= 360; + } + float startAngle = ratio * (endNoteAngle - startNoteAngle) + startNoteAngle; + float endAngle = ratio * ((endNoteAngle - prevInfo.ArcLength) - (startNoteAngle - info.ArcLength)) + + (startNoteAngle - info.ArcLength); + float arcLength = startAngle - endAngle; + + GraphicsPath path = new GraphicsPath(); + path.AddArc(info.Rect, info.StartAngle, info.ArcLength); + path.AddArc(currentInfo.Rect, startAngle + arcLength, -arcLength); + bufGraphics.Graphics.FillPath(HoldBrush, path); + } + + // If the next note is on-screen, this case handles that + if (note.NextNote != null && note.NextNote.Measure <= (CurrentMeasure + TotalMeasureShowNotes)) + { + ArcInfo nextInfo = GetArcInfo((Note)note.NextNote); + GraphicsPath path = new GraphicsPath(); + path.AddArc(info.Rect, info.StartAngle, info.ArcLength); + path.AddArc(nextInfo.Rect, nextInfo.StartAngle + nextInfo.ArcLength, -nextInfo.ArcLength); + bufGraphics.Graphics.FillPath(HoldBrush, path); + } + + // If the next note is off-screen, this case handles that + if (note.NextNote != null && note.NextNote.Measure > (CurrentMeasure + TotalMeasureShowNotes)) + { + ArcInfo nextInfo = GetArcInfo((Note)note.NextNote); + float ratio = (endInfo.Rect.Width - nextInfo.Rect.Width) / (info.Rect.Width - nextInfo.Rect.Width); + float startNoteAngle = nextInfo.StartAngle; + float endNoteAngle = info.StartAngle; + if (nextInfo.StartAngle > info.StartAngle && (Math.Abs(nextInfo.StartAngle - info.StartAngle) > 180)) + { + startNoteAngle -= 360; + } + else if (info.StartAngle > nextInfo.StartAngle && (Math.Abs(nextInfo.StartAngle - info.StartAngle) > 180)) + { + endNoteAngle -= 360; + } + float startAngle = ratio * (endNoteAngle - startNoteAngle) + startNoteAngle; + float endAngle = ratio * ((endNoteAngle - info.ArcLength) - (startNoteAngle - nextInfo.ArcLength)) + + (startNoteAngle - nextInfo.ArcLength); + float arcLength = startAngle - endAngle; + + GraphicsPath path = new GraphicsPath(); + path.AddArc(endInfo.Rect, startAngle, arcLength); + path.AddArc(info.Rect, info.StartAngle + info.ArcLength, -info.ArcLength); + bufGraphics.Graphics.FillPath(HoldBrush, path); + } + + // Draw note + if (info.Rect.Width >= 1) + { + bufGraphics.Graphics.DrawArc(GetPen(note), info.Rect, info.StartAngle, info.ArcLength); + + // Draw bonus + if (note.IsFlair) + bufGraphics.Graphics.DrawArc(HighlightPen, info.Rect, info.StartAngle + 2, info.ArcLength - 4); + + // Plot highlighted + if (highlightSelectedNote) + { + if (selectedNoteIndex != -1 && note == chart.Notes[selectedNoteIndex]) + { + bufGraphics.Graphics.DrawArc(HighlightPen, info.Rect, info.StartAngle + 2, info.ArcLength - 4); + } + } + } + } + } + + public void DrawNotes(Chart chart, bool highlightSelectedNote, int selectedNoteIndex) + { + List drawNotes = chart.Notes.Where( + x => x.Measure >= CurrentMeasure + && x.Measure <= (CurrentMeasure + TotalMeasureShowNotes) + && !x.IsHold && !x.IsMask).ToList(); + foreach (var note in drawNotes) + { + ArcInfo info = GetArcInfo(note); + + if (info.Rect.Width >= 1) + { + bufGraphics.Graphics.DrawArc(GetPen(note, info.NoteScale), info.Rect, info.StartAngle, info.ArcLength); + if (note.IsFlair) + { + bufGraphics.Graphics.DrawArc(FlairPen, info.Rect, info.StartAngle + 2, info.ArcLength - 4); + } + // Plot highlighted + if (highlightSelectedNote) + { + if (selectedNoteIndex != -1 && note == chart.Notes[selectedNoteIndex]) + { + bufGraphics.Graphics.DrawArc(HighlightPen, info.Rect, info.StartAngle + 2, info.ArcLength - 4); + } + } + } + } + } + + public void DrawCursor(NoteType noteType, float startAngle, float sweepAngle) + { + bufGraphics.Graphics.DrawArc( + GetPen(noteType), + DrawRect, + -(float)startAngle * 6.0f, + -(float)sweepAngle * 6.0f); + } + + public void Render(Graphics graphics) + { + bufGraphics.Render(graphics); + } + + public void SetBufferedGraphicsContext(int width, int height, Graphics graphics) + { + gfxContext.MaximumBuffer = new Size(width + 1, height + 1); + bufGraphics = gfxContext.Allocate(graphics, new Rectangle(0, 0, width, height)); + } + public Pen GetPen(Note note, float noteScale = 1.0f) { return new Pen(note.Color, PanelSize.Width * 8.0f * noteScale / 600.0f); diff --git a/BAKKA-Editor/MainForm.cs b/BAKKA-Editor/MainForm.cs index c959620..c595a8c 100644 --- a/BAKKA-Editor/MainForm.cs +++ b/BAKKA-Editor/MainForm.cs @@ -17,9 +17,7 @@ namespace BAKKA_Editor // Operations OperationManager opManager = new OperationManager(); - // Graphics - BufferedGraphicsContext gfxContext = BufferedGraphicsManager.Current; - BufferedGraphics bufGraphics; + // Playfield CircleView circleView = new CircleView(new SizeF(611, 611)); // Note Selection @@ -30,13 +28,6 @@ namespace BAKKA_Editor int selectedNoteIndex = -1; Note lastNote; - // Mouse - int mouseDownPos = -1; - Point mouseDownPt; - int lastMousePos = -1; - bool rolloverPos = false; - bool rolloverNeg = false; - // Music ISoundEngine soundEngine = new ISoundEngine(); ISound currentSong; @@ -175,13 +166,6 @@ namespace BAKKA_Editor Text = $"{save}BAKKA Editor {fileVersion} - [{name}]"; } - private void SetBufferedGraphicsContext() - { - gfxContext.MaximumBuffer = new Size(circlePanel.Width + 1, circlePanel.Height + 1); - bufGraphics = gfxContext.Allocate(circlePanel.CreateGraphics(), - new Rectangle(0, 0, circlePanel.Width, circlePanel.Height)); - } - /// /// Prompts for a save if the chart is not currently saved. /// @@ -506,256 +490,26 @@ namespace BAKKA_Editor private void circlePanel_Paint(object sender, PaintEventArgs e) { - Rectangle panelRect = new Rectangle(0, 0, circlePanel.Width, circlePanel.Height); - - // Set drawing mode - bufGraphics.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed; - // Draw background - bufGraphics.Graphics.FillRectangle(new SolidBrush(this.BackColor), panelRect); - - // Set hi-speed + circleView.DrawBackground(circlePanel.Width, circlePanel.Height, this.BackColor); // Draw masks - var masks = chart.Notes.Where( - x => x.Measure <= circleView.CurrentMeasure - && x.IsMask).ToList(); - foreach (var mask in masks) - { - if (mask.NoteType == NoteType.MaskAdd) - { - // Check if there's a MaskRemove that counters the MaskAdd (unless the MaskAdd is later) - var rem = masks.FirstOrDefault(x => x.NoteType == NoteType.MaskRemove && x.Position == mask.Position && x.Size == mask.Size); - if (rem == null || rem.Measure < mask.Measure) - bufGraphics.Graphics.FillPie(circleView.MaskBrush, circleView.DrawRect.ToInt(), -mask.Position * 6.0f, -mask.Size * 6.0f); - } - } + circleView.DrawMasks(chart); - // Draw selected mask - - // Switch drawing modes - bufGraphics.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; - - // Draw measure circle - for (float meas = (float)Math.Ceiling(circleView.CurrentMeasure); (meas - circleView.CurrentMeasure) < circleView.TotalMeasureShowNotes; meas += 1.0f) - { - var info = circleView.GetScaledRect(meas); - if (info.Rect.Width >= 1) - { - bufGraphics.Graphics.DrawEllipse(circleView.BeatPen, info.Rect); - } - } - - // Draw base circle - bufGraphics.Graphics.DrawEllipse(circleView.TickMediumPen, circleView.DrawRect); + // Draw base and measure circle. + circleView.DrawCircle(); // Draw degree lines - for (int i = 0; i < 360; i += 6) - { - PointF startPoint = new PointF( - (float)(circleView.Radius * Math.Cos(Utils.DegToRad(i))) + circleView.CenterPoint.X, - (float)(circleView.Radius * Math.Sin(Utils.DegToRad(i))) + circleView.CenterPoint.Y); - float tickLength = circleView.PanelSize.Width * 10.0f / 285.0f; - float innerRad = circleView.Radius - tickLength; - Pen activePen; - if (i % 90 == 0) - { - innerRad = circleView.Radius - (tickLength * 3.5f); - activePen = circleView.TickMajorPen; - } - else if (i % 30 == 0) - { - innerRad = circleView.Radius - (tickLength * 2.5f); - activePen = circleView.TickMediumPen; - } - else - { - activePen = circleView.TickMinorPen; - } - PointF endPoint = new PointF( - (float)(innerRad * Math.Cos(Utils.DegToRad(i))) + circleView.CenterPoint.X, - (float)(innerRad * Math.Sin(Utils.DegToRad(i))) + circleView.CenterPoint.Y); - - bufGraphics.Graphics.DrawLine(activePen, startPoint, endPoint); - } - - // Some variables for use later - ArcInfo currentInfo = circleView.GetScaledRect(circleView.CurrentMeasure); - ArcInfo endInfo = circleView.GetScaledRect(circleView.CurrentMeasure + circleView.TotalMeasureShowNotes); + circleView.DrawDegreeLines(); // Draw holds - // First, draw holes that start before the viewpoint and have nodes that end after - List holdNotes = chart.Notes.Where( - x => x.Measure < circleView.CurrentMeasure - && x.NextNote != null - && x.NextNote.Measure > (circleView.CurrentMeasure + circleView.TotalMeasureShowNotes) - && x.IsHold).ToList(); - foreach (var note in holdNotes) - { - ArcInfo info = circleView.GetArcInfo(note); - ArcInfo nextInfo = circleView.GetArcInfo((Note)note.NextNote); - //GraphicsPath path = new GraphicsPath(); - //path.AddArc(endInfo.Rect, info.StartAngle, info.ArcLength); - //path.AddArc(currentInfo.Rect, info.StartAngle + info.ArcLength, -info.ArcLength); - //bufGraphics.Graphics.FillPath(circleView.HoldBrush, path); - - float ratio = (currentInfo.Rect.Width - nextInfo.Rect.Width) / (info.Rect.Width - nextInfo.Rect.Width); - float startNoteAngle = nextInfo.StartAngle; - float endNoteAngle = info.StartAngle; - if (nextInfo.StartAngle > info.StartAngle && (Math.Abs(nextInfo.StartAngle - info.StartAngle) > 180)) - { - startNoteAngle -= 360; - } - else if (info.StartAngle > nextInfo.StartAngle && (Math.Abs(nextInfo.StartAngle - info.StartAngle) > 180)) - { - endNoteAngle -= 360; - } - float startAngle = ratio * (endNoteAngle - startNoteAngle) + startNoteAngle; - float endAngle = ratio * ((endNoteAngle - info.ArcLength) - (startNoteAngle - nextInfo.ArcLength)) + - (startNoteAngle - nextInfo.ArcLength); - float arcLength = startAngle - endAngle; - - float ratio2 = (endInfo.Rect.Width - nextInfo.Rect.Width) / (info.Rect.Width - nextInfo.Rect.Width); - float startNoteAngle2 = nextInfo.StartAngle; - float endNoteAngle2 = info.StartAngle; - if (nextInfo.StartAngle > info.StartAngle && (Math.Abs(nextInfo.StartAngle - info.StartAngle) > 180)) - { - startNoteAngle2 -= 360; - } - else if (info.StartAngle > nextInfo.StartAngle && (Math.Abs(nextInfo.StartAngle - info.StartAngle) > 180)) - { - endNoteAngle2 -= 360; - } - float startAngle2 = ratio2 * (endNoteAngle2 - startNoteAngle2) + startNoteAngle2; - float endAngle2 = ratio2 * ((endNoteAngle2 - info.ArcLength) - (startNoteAngle2 - nextInfo.ArcLength)) + - (startNoteAngle2 - nextInfo.ArcLength); - float arcLength2 = startAngle2 - endAngle2; - - GraphicsPath path = new GraphicsPath(); - path.AddArc(currentInfo.Rect, startAngle, arcLength); - path.AddArc(endInfo.Rect, startAngle2 + arcLength2, -arcLength2); - bufGraphics.Graphics.FillPath(circleView.HoldBrush, path); - } - // Second, draw all the notes on-screen - holdNotes = chart.Notes.Where( - x => x.Measure >= circleView.CurrentMeasure - && x.Measure <= (circleView.CurrentMeasure + circleView.TotalMeasureShowNotes) - && x.IsHold).ToList(); - foreach (var note in holdNotes) - { - ArcInfo info = circleView.GetArcInfo(note); - - // If the previous note is off-screen, this case handles that - if (note.PrevNote != null && note.PrevNote.Measure < circleView.CurrentMeasure) - { - ArcInfo prevInfo = circleView.GetArcInfo((Note)note.PrevNote); - float ratio = (currentInfo.Rect.Width - info.Rect.Width) / (prevInfo.Rect.Width - info.Rect.Width); - float startNoteAngle = info.StartAngle; - float endNoteAngle = prevInfo.StartAngle; - if (info.StartAngle > prevInfo.StartAngle && (Math.Abs(info.StartAngle - prevInfo.StartAngle) > 180)) - { - startNoteAngle -= 360; - } - else if (prevInfo.StartAngle > info.StartAngle && (Math.Abs(info.StartAngle - prevInfo.StartAngle) > 180)) - { - endNoteAngle -= 360; - } - float startAngle = ratio * (endNoteAngle - startNoteAngle) + startNoteAngle; - float endAngle = ratio * ((endNoteAngle - prevInfo.ArcLength) - (startNoteAngle - info.ArcLength)) + - (startNoteAngle - info.ArcLength); - float arcLength = startAngle - endAngle; - - GraphicsPath path = new GraphicsPath(); - path.AddArc(info.Rect, info.StartAngle, info.ArcLength); - path.AddArc(currentInfo.Rect, startAngle + arcLength, -arcLength); - bufGraphics.Graphics.FillPath(circleView.HoldBrush, path); - } - - // If the next note is on-screen, this case handles that - if (note.NextNote != null && note.NextNote.Measure <= (circleView.CurrentMeasure + circleView.TotalMeasureShowNotes)) - { - ArcInfo nextInfo = circleView.GetArcInfo((Note)note.NextNote); - GraphicsPath path = new GraphicsPath(); - path.AddArc(info.Rect, info.StartAngle, info.ArcLength); - path.AddArc(nextInfo.Rect, nextInfo.StartAngle + nextInfo.ArcLength, -nextInfo.ArcLength); - bufGraphics.Graphics.FillPath(circleView.HoldBrush, path); - } - - // If the next note is off-screen, this case handles that - if (note.NextNote != null && note.NextNote.Measure > (circleView.CurrentMeasure + circleView.TotalMeasureShowNotes)) - { - ArcInfo nextInfo = circleView.GetArcInfo((Note)note.NextNote); - float ratio = (endInfo.Rect.Width - nextInfo.Rect.Width) / (info.Rect.Width - nextInfo.Rect.Width); - float startNoteAngle = nextInfo.StartAngle; - float endNoteAngle = info.StartAngle; - if (nextInfo.StartAngle > info.StartAngle && (Math.Abs(nextInfo.StartAngle - info.StartAngle) > 180)) - { - startNoteAngle -= 360; - } - else if (info.StartAngle > nextInfo.StartAngle && (Math.Abs(nextInfo.StartAngle - info.StartAngle) > 180)) - { - endNoteAngle -= 360; - } - float startAngle = ratio * (endNoteAngle - startNoteAngle) + startNoteAngle; - float endAngle = ratio * ((endNoteAngle - info.ArcLength) - (startNoteAngle - nextInfo.ArcLength)) + - (startNoteAngle - nextInfo.ArcLength); - float arcLength = startAngle - endAngle; - - GraphicsPath path = new GraphicsPath(); - path.AddArc(endInfo.Rect, startAngle, arcLength); - path.AddArc(info.Rect, info.StartAngle + info.ArcLength, -info.ArcLength); - bufGraphics.Graphics.FillPath(circleView.HoldBrush, path); - } - - // Draw note - if (info.Rect.Width >= 1) - { - bufGraphics.Graphics.DrawArc(circleView.GetPen(note), info.Rect, info.StartAngle, info.ArcLength); - - // Draw bonus - if (note.IsFlair) - bufGraphics.Graphics.DrawArc(circleView.HighlightPen, info.Rect, info.StartAngle + 2, info.ArcLength - 4); - - // Plot highlighted - if (highlightViewedNoteToolStripMenuItem.Checked) - { - if (selectedNoteIndex != -1 && note == chart.Notes[selectedNoteIndex]) - { - bufGraphics.Graphics.DrawArc(circleView.HighlightPen, info.Rect, info.StartAngle + 2, info.ArcLength - 4); - } - } - } - } + circleView.DrawHolds(chart, highlightViewedNoteToolStripMenuItem.Checked, selectedNoteIndex); // Draw notes - List drawNotes = chart.Notes.Where( - x => x.Measure >= circleView.CurrentMeasure - && x.Measure <= (circleView.CurrentMeasure + circleView.TotalMeasureShowNotes) - && !x.IsHold && !x.IsMask).ToList(); - foreach (var note in drawNotes) - { - ArcInfo info = circleView.GetArcInfo(note); - - if (info.Rect.Width >= 1) - { - bufGraphics.Graphics.DrawArc(circleView.GetPen(note, info.NoteScale), info.Rect, info.StartAngle, info.ArcLength); - if (note.IsFlair) - { - bufGraphics.Graphics.DrawArc(circleView.FlairPen, info.Rect, info.StartAngle + 2, info.ArcLength - 4); - } - // Plot highlighted - if (highlightViewedNoteToolStripMenuItem.Checked) - { - if (selectedNoteIndex != -1 && note == chart.Notes[selectedNoteIndex]) - { - bufGraphics.Graphics.DrawArc(circleView.HighlightPen, info.Rect, info.StartAngle + 2, info.ArcLength - 4); - } - } - } - } + circleView.DrawNotes(chart, highlightViewedNoteToolStripMenuItem.Checked, selectedNoteIndex); // Determine if cursor should be showing - bool showCursor = showCursorToolStripMenuItem.Checked || mouseDownPos != -1; + bool showCursor = showCursorToolStripMenuItem.Checked || circleView.mouseDownPos != -1; if (currentSong != null && !currentSong.Paused) { showCursor = showCursorDuringPlaybackToolStripMenuItem.Checked; @@ -764,14 +518,11 @@ namespace BAKKA_Editor // Draw cursor if (showCursor) { - bufGraphics.Graphics.DrawArc( - circleView.GetPen(currentNoteType), - circleView.DrawRect, - -(float)positionNumeric.Value * 6.0f, - -(float)sizeNumeric.Value * 6.0f); + circleView.DrawCursor(currentNoteType, (float)positionNumeric.Value, (float)sizeNumeric.Value); } - bufGraphics.Render(e.Graphics); + // Everything has been drawn, render it. + circleView.Render(e.Graphics); } private void measureNumeric_ValueChanged(object sender, EventArgs e) @@ -1232,92 +983,72 @@ namespace BAKKA_Editor private void circlePanel_MouseDown(object sender, MouseEventArgs e) { - // Determine the location of mouse click inside the circle + if (e.Button != MouseButtons.Left) + { + return; + } + // X and Y are relative to the upper left of the panel float xCen = e.X - (circlePanel.Width / 2); float yCen = -(e.Y - (circlePanel.Height / 2)); - float theta = (float)(Math.Atan2(yCen, xCen) * 180.0f / Math.PI); - if (theta < 0) - theta += 360.0f; - // Left click moves the cursor - if (e.Button == MouseButtons.Left) - { - positionNumeric.Value = (int)(theta / 6.0f); - mouseDownPos = (int)positionNumeric.Value; - mouseDownPt = e.Location; - lastMousePos = -1; - rolloverPos = false; - rolloverNeg = false; - circlePanel.Invalidate(); - } + // Update the location of mouse click inside the circle + circleView.UpdateMouseDown(xCen, yCen, e.Location); + positionNumeric.Value = circleView.mouseDownPos; + circlePanel.Invalidate(); } private void circlePanel_MouseUp(object sender, MouseEventArgs e) { - if (e.Button == MouseButtons.Left && mouseDownPos > -1) + // Mouse down position wasn't within the window or wasn't a left click, do nothing. + if (e.Button != MouseButtons.Left || circleView.mouseDownPos <= -1) { - var dist = Utils.GetDist(e.Location, mouseDownPt); - if (dist > 5.0f) - InsertObject(); - mouseDownPos = -1; - mouseDownPt = new Point(); - circlePanel.Invalidate(); + return; } + + var dist = Utils.GetDist(e.Location, circleView.mouseDownPt); + if (dist > 5.0f) + InsertObject(); + circleView.UpdateMouseUp(); + circlePanel.Invalidate(); } private void circlePanel_MouseMove(object sender, MouseEventArgs e) { - // Determine the location of mouse click inside the circle + // Mouse down position wasn't within the window or wasn't a left click, do nothing. + if (e.Button != MouseButtons.Left || circleView.mouseDownPos <= -1) + { + return; + } + // X and Y are relative to the upper left of the panel float xCen = e.X - (circlePanel.Width / 2); float yCen = -(e.Y - (circlePanel.Height / 2)); - float thetaCalc = (float)(Math.Atan2(yCen, xCen) * 180.0f / Math.PI); - if (thetaCalc < 0) - thetaCalc += 360.0f; - int theta = (int)(thetaCalc / 6.0f); + // Update the location of mouse click inside the circle. + int theta = circleView.UpdateMouseMove(xCen, yCen); // Left click will alter the note width and possibly position depending on which direction we move - if (e.Button == MouseButtons.Left && mouseDownPos != -1) + if (theta == circleView.mouseDownPos) { - int delta = theta - lastMousePos; - // Handle rollover - if (delta == -59) - { - if (rolloverNeg) - rolloverNeg = false; - else - rolloverPos = true; - } - else if (delta == 59) - { - if (rolloverPos) - rolloverPos = false; - else - rolloverNeg = true; - } - if (theta == mouseDownPos) - { - positionNumeric.Value = mouseDownPos; - sizeNumeric.Value = 1; - } - else if ((theta > mouseDownPos || rolloverPos) && !rolloverNeg) - { - positionNumeric.Value = mouseDownPos; - if (rolloverPos) - sizeNumeric.Value = (int)Math.Min(theta + 60 - mouseDownPos + 1, 60); - else - sizeNumeric.Value = theta - mouseDownPos + 1; - } - else if (theta < mouseDownPos || rolloverNeg) - { - positionNumeric.Value = theta; - if (rolloverNeg) - sizeNumeric.Value = (int)Math.Min(mouseDownPos + 60 - theta + 1, 60); - else - sizeNumeric.Value = mouseDownPos - theta + 1; - } - lastMousePos = theta; - circlePanel.Invalidate(); + positionNumeric.Value = circleView.mouseDownPos; + sizeNumeric.Value = 1; } + else if ((theta > circleView.mouseDownPos || circleView.rolloverPos) && !circleView.rolloverNeg) + { + positionNumeric.Value = circleView.mouseDownPos; + if (circleView.rolloverPos) + sizeNumeric.Value = (int)Math.Min(theta + 60 - circleView.mouseDownPos + 1, 60); + else + sizeNumeric.Value = theta - circleView.mouseDownPos + 1; + } + else if (theta < circleView.mouseDownPos || circleView.rolloverNeg) + { + positionNumeric.Value = theta; + if (circleView.rolloverNeg) + sizeNumeric.Value = (int)Math.Min(circleView.mouseDownPos + 60 - theta + 1, 60); + else + sizeNumeric.Value = circleView.mouseDownPos - theta + 1; + } + + circlePanel.Invalidate(); } private void visualHispeedNumeric_ValueChanged(object sender, EventArgs e) @@ -2123,7 +1854,7 @@ namespace BAKKA_Editor circlePanel.Invalidate(); } - private void MainForm_Resize(object sender, EventArgs e) + private void MainForm_Resize(object sender, EventArgs e) { var zoneWidth = noteViewGroupBox.Left - gimmickTypeGroupBox.Right - 12; var zoneHeight = playbackGroupBox.Top - gimmickTypeGroupBox.Top - 6; @@ -2139,7 +1870,7 @@ namespace BAKKA_Editor } int paddingLeft = (zoneWidth - circlePanel.Width) / 2; circlePanel.Left = gimmickTypeGroupBox.Right + 6 + paddingLeft; - SetBufferedGraphicsContext(); + circleView.SetBufferedGraphicsContext(circlePanel.Width, circlePanel.Height, circlePanel.CreateGraphics()); circleView.Update(circlePanel.Size); circlePanel.Invalidate(); }