protected override void OnRender(RenderGraphics g) { g.Clear(ThemeBase.DarkGreyFillColor1); int seekX = ScaleForZoom(App.CurrentFrame) - scrollX; int minVisiblePattern = Math.Max((int)Math.Floor(scrollX / (float)patternSizeX), 0); int maxVisiblePattern = Math.Min((int)Math.Ceiling((scrollX + Width) / (float)patternSizeX), Song.Length); // Track name background g.FillRectangle(0, 0, trackNameSizeX, Height, whiteKeyBrush); if (IsSelectionValid()) { g.PushClip(trackNameSizeX, 0, Width, headerSizeY); g.PushTranslation(trackNameSizeX, 0); g.FillRectangle( (minSelectedPatternIdx + 0) * patternSizeX - scrollX, 0, (maxSelectedPatternIdx + 1) * patternSizeX - scrollX, headerSizeY, showSelection ? selectedPatternVisibleBrush : selectedPatternInvisibleBrush); g.PopTransform(); g.PopClip(); } // Header g.DrawLine(0, 0, Width, 0, theme.BlackBrush); g.DrawLine(trackNameSizeX - 1, 0, trackNameSizeX - 1, headerSizeY, theme.DarkGreyLineBrush1); g.PushTranslation(trackNameSizeX, 0); g.PushClip(0, 0, Width, Height); for (int i = minVisiblePattern, x = minVisiblePattern * patternSizeX - scrollX; i <= maxVisiblePattern; i++, x += patternSizeX) { if (i != 0) { g.DrawLine(x, 0, x, Height, theme.DarkGreyLineBrush1); } } for (int i = minVisiblePattern, x = minVisiblePattern * patternSizeX - scrollX; i < maxVisiblePattern; i++, x += patternSizeX) { g.PushTranslation(x, 0); g.DrawText(i.ToString(), ThemeBase.FontMediumCenter, 0, barTextPosY, theme.LightGreyFillBrush1, patternSizeX); g.PopTransform(); } g.PushTranslation(seekX, 0); g.FillAndDrawConvexPath(seekGeometry, seekBarBrush, theme.BlackBrush); g.PopTransform(); g.PopClip(); g.PopTransform(); g.PushTranslation(0, headerSizeY); if (Song.Project.NeedsExpansionInstruments) { for (int i = Channel.ExpansionAudioStart; i < Song.Channels.Length; i++) { g.FillRectangle(0, i * trackSizeY, expansionTypeSizeX, (i + 1) * trackSizeY + 1, theme.MediumGreyFillBrush1); } g.PushTranslation(expansionTypeSizeX, 0); g.DrawLine(0, 0, 0, Height, theme.DarkGreyLineBrush1); } // Icons for (int i = 0, y = 0; i < Song.Channels.Length; i++, y += trackSizeY) { g.DrawBitmap(bmpTracks[(int)Song.Channels[i].Type], trackIconPosX, y + trackIconPosY, (App.ChannelMask & (1 << i)) != 0 ? 1.0f : 0.2f); } // Track names for (int i = 0, y = 0; i < Song.Channels.Length; i++, y += trackSizeY) { g.DrawText(Song.Channels[i].Name, i == selectedChannel ? ThemeBase.FontMediumBold : ThemeBase.FontMedium, trackNamePosX, y + trackNamePosY, theme.BlackBrush); } if (Song.Project.NeedsExpansionInstruments) { g.PopTransform(); } // Ghost note icons for (int i = 0, y = 0; i < Song.Channels.Length; i++, y += trackSizeY) { g.DrawBitmap(bmpGhostNote, trackNameSizeX - ghostNoteOffsetX, y + trackSizeY - ghostNoteOffsetY - 1, (App.GhostChannelMask & (1 << i)) != 0 ? 1.0f : 0.2f); } // Vertical line seperating the track labels. g.DrawLine(trackNameSizeX - 1, 0, trackNameSizeX - 1, Height, theme.DarkGreyLineBrush1); // Grey background rectangles ever other pattern + vertical lines g.PushClip(trackNameSizeX, 0, Width, Height); g.PushTranslation(trackNameSizeX, 0); for (int i = minVisiblePattern, x = minVisiblePattern * patternSizeX - scrollX; i < maxVisiblePattern; i++, x += patternSizeX) { if ((i & 1) == 0) { g.FillRectangle(x, 0, x + patternSizeX, Height, theme.DarkGreyFillBrush2); } } for (int i = minVisiblePattern, x = minVisiblePattern * patternSizeX - scrollX; i <= maxVisiblePattern; i++, x += patternSizeX) { if (i != 0) { g.DrawLine(x, 0, x, Height, theme.DarkGreyLineBrush1); } } if (IsSelectionValid()) { g.FillRectangle( (minSelectedPatternIdx + 0) * patternSizeX - scrollX, trackSizeY * (minSelectedChannelIdx + 0), (maxSelectedPatternIdx + 1) * patternSizeX - scrollX, trackSizeY * (maxSelectedChannelIdx + 1), showSelection ? selectedPatternVisibleBrush : selectedPatternInvisibleBrush); } g.PopTransform(); g.PopClip(); // Horizontal lines for (int i = 0, y = 0; i < Song.Channels.Length; i++, y += trackSizeY) { g.DrawLine(0, y, Width, y, theme.DarkGreyLineBrush1); } g.PushClip(trackNameSizeX, 0, Width, Height); // Seek g.DrawLine(seekX + trackNameSizeX, 1, seekX + trackNameSizeX, Height, seekBarBrush, 3); // Patterns for (int t = 0, y = 0; t < Song.Channels.Length; t++, y += trackSizeY) { for (int i = minVisiblePattern, x = minVisiblePattern * patternSizeX + trackNameSizeX - scrollX; i < maxVisiblePattern; i++, x += patternSizeX) { var pattern = Song.Channels[t].PatternInstances[i]; if (pattern != null) { //var selected = IsPatternSelected(t, i); var bmp = GetPatternBitmapFromCache(g, pattern); g.PushTranslation(x, y); g.FillRectangle(1, 1, patternSizeX, patternHeaderSizeY, g.GetVerticalGradientBrush(pattern.Color, patternHeaderSizeY - 1, 0.9f)); g.DrawLine(0, patternHeaderSizeY, patternSizeX, patternHeaderSizeY, theme.DarkGreyLineBrush1); //if (selected) // g.FillRectangle(1, 1 + patternHeaderSizeY, patternSizeX, patternHeaderSizeY + bmp.Size.Height + 1, showSelection ? selectedPatternVisibleBrush : selectedPatternInvisibleBrush); g.DrawBitmap(bmp, 1, 1 + patternHeaderSizeY, patternSizeX - 1, bmp.Size.Height, 1.0f); g.PushClip(0, 0, patternSizeX, trackSizeY); g.DrawText(pattern.Name, ThemeBase.FontSmall, patternNamePosX, patternNamePosY, theme.BlackBrush); g.PopClip(); g.PopTransform(); } } } // Dragging selection if (captureOperation == CaptureOperation.DragSelection) { var pt = this.PointToClient(Cursor.Position); //pt.X -= TrackNameSizeX; pt.Y -= headerSizeY; var drawX = pt.X - selectionDragAnchorX; var drawY = minSelectedChannelIdx * trackSizeY; var sizeX = (maxSelectedPatternIdx - minSelectedPatternIdx + 1) * patternSizeX; var sizeY = (maxSelectedChannelIdx - minSelectedChannelIdx + 1) * trackSizeY; g.FillRectangle(drawX, drawY, drawX + sizeX, drawY + sizeY, showSelection ? selectedPatternVisibleBrush : selectedPatternInvisibleBrush); } g.PopClip(); g.PopTransform(); g.DrawLine(0, Height - 1, Width, Height - 1, theme.DarkGreyLineBrush1); }